From 74be44ddff8b5047ae84291336149ff0df632f79 Mon Sep 17 00:00:00 2001 From: Kim Low Date: Fri, 6 Nov 2020 12:45:07 -0800 Subject: Added the ability to read external batteries Extended InputDevice and EventHub with capabilites to detect and read external battery status and capacity. This allows devices such as wireless gamepads to provide battery information to applications. Bug: 161633432 Test: atest InputDeviceBatteryTest Change-Id: I3c65166a1f0b055c5b85bad286afd5beb60bb303 --- include/input/InputDevice.h | 4 + libs/input/InputDevice.cpp | 2 + libs/input/android/os/IInputConstants.aidl | 3 + services/inputflinger/include/InputReaderBase.h | 4 + services/inputflinger/reader/Android.bp | 5 + services/inputflinger/reader/EventHub.cpp | 149 +++++++++++++++++++++ services/inputflinger/reader/InputDevice.cpp | 15 +++ services/inputflinger/reader/InputReader.cpp | 20 +++ services/inputflinger/reader/include/EventHub.h | 20 +++ services/inputflinger/reader/include/InputDevice.h | 9 ++ services/inputflinger/reader/include/InputReader.h | 4 + .../reader/mapper/BatteryInputMapper.cpp | 72 ++++++++++ .../reader/mapper/BatteryInputMapper.h | 41 ++++++ services/inputflinger/reader/mapper/InputMapper.h | 3 + services/inputflinger/tests/InputReader_test.cpp | 79 +++++++++++ 15 files changed, 430 insertions(+) create mode 100644 services/inputflinger/reader/mapper/BatteryInputMapper.cpp create mode 100644 services/inputflinger/reader/mapper/BatteryInputMapper.h diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h index 23692e92d4..2bd7bd2004 100644 --- a/include/input/InputDevice.h +++ b/include/input/InputDevice.h @@ -213,6 +213,9 @@ public: inline void setVibrator(bool hasVibrator) { mHasVibrator = hasVibrator; } inline bool hasVibrator() const { return mHasVibrator; } + inline void setHasBattery(bool hasBattery) { mHasBattery = hasBattery; } + inline bool hasBattery() const { return mHasBattery; } + inline void setButtonUnderPad(bool hasButton) { mHasButtonUnderPad = hasButton; } inline bool hasButtonUnderPad() const { return mHasButtonUnderPad; } @@ -239,6 +242,7 @@ private: int32_t mKeyboardType; std::shared_ptr mKeyCharacterMap; bool mHasVibrator; + bool mHasBattery; bool mHasButtonUnderPad; bool mHasSensor; diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp index 2ed441d8b4..698cf6eebc 100644 --- a/libs/input/InputDevice.cpp +++ b/libs/input/InputDevice.cpp @@ -166,6 +166,7 @@ InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) mKeyboardType(other.mKeyboardType), mKeyCharacterMap(other.mKeyCharacterMap), mHasVibrator(other.mHasVibrator), + mHasBattery(other.mHasBattery), mHasButtonUnderPad(other.mHasButtonUnderPad), mHasSensor(other.mHasSensor), mMotionRanges(other.mMotionRanges), @@ -187,6 +188,7 @@ void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t control mSources = 0; mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE; mHasVibrator = false; + mHasBattery = false; mHasButtonUnderPad = false; mHasSensor = false; mMotionRanges.clear(); diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl index 6316b59a57..c69a53a784 100644 --- a/libs/input/android/os/IInputConstants.aidl +++ b/libs/input/android/os/IInputConstants.aidl @@ -28,4 +28,7 @@ interface IInputConstants * to identify apps that are using this flag. */ const long BLOCK_FLAG_SLIPPERY = 157929241; + + // Indicate invalid battery capacity + const int INVALID_BATTERY_CAPACITY = -1; } diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index ea9b48368e..69aea84cd0 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -108,6 +108,10 @@ public: virtual bool isVibrating(int32_t deviceId) = 0; virtual std::vector getVibratorIds(int32_t deviceId) = 0; + /* Get battery level of a particular input device. */ + virtual std::optional getBatteryCapacity(int32_t deviceId) = 0; + /* Get battery status of a particular input device. */ + virtual std::optional getBatteryStatus(int32_t deviceId) = 0; /* Return true if the device can send input events to the specified display. */ virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId) = 0; diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp index abda4ef45c..7f979f2bd3 100644 --- a/services/inputflinger/reader/Android.bp +++ b/services/inputflinger/reader/Android.bp @@ -30,6 +30,7 @@ filegroup { "mapper/accumulator/CursorScrollAccumulator.cpp", "mapper/accumulator/SingleTouchMotionAccumulator.cpp", "mapper/accumulator/TouchButtonAccumulator.cpp", + "mapper/BatteryInputMapper.cpp", "mapper/CursorInputMapper.cpp", "mapper/ExternalStylusInputMapper.cpp", "mapper/InputMapper.cpp", @@ -60,7 +61,11 @@ cc_defaults { "libui", "libutils", ], + static_libs: [ + "libc++fs", + ], header_libs: [ + "libbatteryservice_headers", "libinputreader_headers", ], } diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index b97ff909d6..8f8c0513b2 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -29,11 +29,14 @@ #include #include #include +#include +#include #include #define LOG_TAG "EventHub" // #define LOG_NDEBUG 0 +#include #include #include #include @@ -64,6 +67,23 @@ static const char* VIDEO_DEVICE_PATH = "/dev"; static constexpr int32_t FF_STRONG_MAGNITUDE_CHANNEL_IDX = 0; static constexpr int32_t FF_WEAK_MAGNITUDE_CHANNEL_IDX = 1; +// must be kept in sync with definitions in kernel /drivers/power/supply/power_supply_sysfs.c +static const std::unordered_map BATTERY_STATUS = + {{"Unknown", BATTERY_STATUS_UNKNOWN}, + {"Charging", BATTERY_STATUS_CHARGING}, + {"Discharging", BATTERY_STATUS_DISCHARGING}, + {"Not charging", BATTERY_STATUS_NOT_CHARGING}, + {"Full", BATTERY_STATUS_FULL}}; + +// Mapping taken from +// https://gitlab.freedesktop.org/upower/upower/-/blob/master/src/linux/up-device-supply.c#L484 +static const std::unordered_map BATTERY_LEVEL = {{"Critical", 5}, + {"Low", 10}, + {"Normal", 55}, + {"High", 70}, + {"Full", 100}, + {"Unknown", 50}}; + static inline const char* toString(bool value) { return value ? "true" : "false"; } @@ -127,6 +147,73 @@ static nsecs_t processEventTimestamp(const struct input_event& event) { return inputEventTime; } +/** + * Returns the sysfs root path of the input device + * + */ +static std::filesystem::path getSysfsRootPath(const char* devicePath) { + std::error_code errorCode; + + // Stat the device path to get the major and minor number of the character file + struct stat statbuf; + if (stat(devicePath, &statbuf) == -1) { + ALOGE("Could not stat device %s due to error: %s.", devicePath, std::strerror(errno)); + return std::filesystem::path(); + } + + unsigned int major_num = major(statbuf.st_rdev); + unsigned int minor_num = minor(statbuf.st_rdev); + + // Realpath "/sys/dev/char/{major}:{minor}" to get the sysfs path to the input event + auto sysfsPath = std::filesystem::path("/sys/dev/char/"); + sysfsPath /= std::to_string(major_num) + ":" + std::to_string(minor_num); + sysfsPath = std::filesystem::canonical(sysfsPath, errorCode); + + // Make sure nothing went wrong in call to canonical() + if (errorCode) { + ALOGW("Could not run filesystem::canonical() due to error %d : %s.", errorCode.value(), + errorCode.message().c_str()); + return std::filesystem::path(); + } + + // Continue to go up a directory until we reach a directory named "input" + while (sysfsPath != "/" && sysfsPath.filename() != "input") { + sysfsPath = sysfsPath.parent_path(); + } + + // Then go up one more and you will be at the sysfs root of the device + sysfsPath = sysfsPath.parent_path(); + + // Make sure we didn't reach root path and that directory actually exists + if (sysfsPath == "/" || !std::filesystem::exists(sysfsPath, errorCode)) { + if (errorCode) { + ALOGW("Could not run filesystem::exists() due to error %d : %s.", errorCode.value(), + errorCode.message().c_str()); + } + + // Not found + return std::filesystem::path(); + } + + return sysfsPath; +} + +/** + * Returns the power supply node in sys fs + * + */ +static std::filesystem::path findPowerSupplyNode(const std::filesystem::path& sysfsRootPath) { + for (auto path = sysfsRootPath; path != "/"; path = path.parent_path()) { + std::error_code errorCode; + auto iter = std::filesystem::directory_iterator(path / "power_supply", errorCode); + if (!errorCode && iter != std::filesystem::directory_iterator()) { + return iter->path(); + } + } + // Not found + return std::filesystem::path(); +} + // --- Global Functions --- Flags getAbsAxisUsage(int32_t axis, Flags deviceClasses) { @@ -976,6 +1063,56 @@ EventHub::Device* EventHub::getDeviceByFdLocked(int fd) const { return nullptr; } +std::optional EventHub::getBatteryCapacity(int32_t deviceId) const { + std::scoped_lock _l(mLock); + Device* device = getDeviceLocked(deviceId); + std::string buffer; + + if (!device || (device->sysfsBatteryPath.empty())) { + return std::nullopt; + } + + // Some devices report battery capacity as an integer through the "capacity" file + if (base::ReadFileToString(device->sysfsBatteryPath / "capacity", &buffer)) { + return std::stoi(buffer); + } + + // Other devices report capacity as an enum value POWER_SUPPLY_CAPACITY_LEVEL_XXX + // These values are taken from kernel source code include/linux/power_supply.h + if (base::ReadFileToString(device->sysfsBatteryPath / "capacity_level", &buffer)) { + const auto it = BATTERY_LEVEL.find(buffer); + if (it != BATTERY_LEVEL.end()) { + return it->second; + } + } + return std::nullopt; +} + +std::optional EventHub::getBatteryStatus(int32_t deviceId) const { + std::scoped_lock _l(mLock); + Device* device = getDeviceLocked(deviceId); + std::string buffer; + + if (!device || (device->sysfsBatteryPath.empty())) { + return std::nullopt; + } + + if (!base::ReadFileToString(device->sysfsBatteryPath / "status", &buffer)) { + ALOGE("Failed to read sysfs battery info: %s", strerror(errno)); + return std::nullopt; + } + + // Remove trailing new line + buffer.erase(std::remove(buffer.begin(), buffer.end(), '\n'), buffer.end()); + const auto it = BATTERY_STATUS.find(buffer); + + if (it != BATTERY_STATUS.end()) { + return it->second; + } + + return std::nullopt; +} + size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { ALOG_ASSERT(bufferSize >= 1); @@ -1584,6 +1721,18 @@ status_t EventHub::openDeviceLocked(const std::string& devicePath) { return -1; } + // Grab the device's sysfs path + device->sysfsRootPath = getSysfsRootPath(devicePath.c_str()); + + if (!device->sysfsRootPath.empty()) { + device->sysfsBatteryPath = findPowerSupplyNode(device->sysfsRootPath); + + // Check if a battery exists + if (!device->sysfsBatteryPath.empty()) { + device->classes |= InputDeviceClass::BATTERY; + } + } + // Determine whether the device has a mic. if (device->deviceHasMicLocked()) { device->classes |= InputDeviceClass::MIC; diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index 3e6910d420..8fc6f4a701 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -21,6 +21,7 @@ #include #include +#include "BatteryInputMapper.h" #include "CursorInputMapper.h" #include "ExternalStylusInputMapper.h" #include "InputReaderContext.h" @@ -160,6 +161,11 @@ void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) { mappers.push_back(std::make_unique(*contextPtr)); } + // Battery-like devices. + if (classes.test(InputDeviceClass::BATTERY)) { + mappers.push_back(std::make_unique(*contextPtr)); + } + // Keyboard-like devices. uint32_t keyboardSource = 0; int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC; @@ -490,6 +496,15 @@ void InputDevice::cancelTouch(nsecs_t when) { for_each_mapper([when](InputMapper& mapper) { mapper.cancelTouch(when); }); } +std::optional InputDevice::getBatteryCapacity() { + return first_in_mappers( + [](InputMapper& mapper) { return mapper.getBatteryCapacity(); }); +} + +std::optional InputDevice::getBatteryStatus() { + return first_in_mappers([](InputMapper& mapper) { return mapper.getBatteryStatus(); }); +} + int32_t InputDevice::getMetaState() { int32_t result = 0; for_each_mapper([&result](InputMapper& mapper) { result |= mapper.getMetaState(); }); diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index 7c448e4efa..de5d0e6442 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -673,6 +673,26 @@ void InputReader::flushSensor(int32_t deviceId, InputDeviceSensorType sensorType } } +std::optional InputReader::getBatteryCapacity(int32_t deviceId) { + std::scoped_lock _l(mLock); + + InputDevice* device = findInputDeviceLocked(deviceId); + if (device) { + return device->getBatteryCapacity(); + } + return std::nullopt; +} + +std::optional InputReader::getBatteryStatus(int32_t deviceId) { + std::scoped_lock _l(mLock); + + InputDevice* device = findInputDeviceLocked(deviceId); + if (device) { + return device->getBatteryStatus(); + } + return std::nullopt; +} + bool InputReader::isInputDeviceEnabled(int32_t deviceId) { std::scoped_lock _l(mLock); diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index 2cea01776a..30967dfdf2 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -23,6 +23,9 @@ #include #include +#include + +#include #include #include #include @@ -121,6 +124,9 @@ enum class InputDeviceClass : uint32_t { /* The input device has a sensor like accelerometer, gyro, etc */ SENSOR = 0x00002000, + /* The input device has a battery */ + BATTERY = 0x00004000, + /* The input device is virtual (not a real device, not part of UI configuration). */ VIRTUAL = 0x40000000, @@ -242,6 +248,12 @@ public: virtual void cancelVibrate(int32_t deviceId) = 0; virtual std::vector getVibratorIds(int32_t deviceId) = 0; + /* Query battery level. */ + virtual std::optional getBatteryCapacity(int32_t deviceId) const = 0; + + /* Query battery status. */ + virtual std::optional getBatteryStatus(int32_t deviceId) const = 0; + /* Requests the EventHub to reopen all input devices on the next call to getEvents(). */ virtual void requestReopenDevices() = 0; @@ -404,6 +416,10 @@ public: void monitor() override final; + std::optional getBatteryCapacity(int32_t deviceId) const override final; + + std::optional getBatteryStatus(int32_t deviceId) const override final; + bool isDeviceEnabled(int32_t deviceId) override final; status_t enableDevice(int32_t deviceId) override final; @@ -442,6 +458,10 @@ private: bool ffEffectPlaying; int16_t ffEffectId; // initially -1 + // The paths are invalid when .empty() returns true + std::filesystem::path sysfsRootPath; + std::filesystem::path sysfsBatteryPath; + int32_t controllerNumber; Device(int fd, int32_t id, const std::string& path, diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index 5af76b7a71..e4186c86cd 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -92,6 +92,9 @@ public: void disableSensor(InputDeviceSensorType sensorType); void flushSensor(InputDeviceSensorType sensorType); + std::optional getBatteryCapacity(); + std::optional getBatteryStatus(); + int32_t getMetaState(); void updateMetaState(int32_t keyCode); @@ -287,6 +290,12 @@ public: inline std::vector getVibratorIds() { return mEventHub->getVibratorIds(mId); } + inline std::optional getBatteryCapacity() { + return mEventHub->getBatteryCapacity(mId); + } + + inline std::optional getBatteryStatus() { return mEventHub->getBatteryStatus(mId); } + inline bool hasAbsoluteAxis(int32_t code) const { RawAbsoluteAxisInfo info; mEventHub->getAbsoluteAxisInfo(mId, code, &info); diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h index 7be932a458..e2558bcf2e 100644 --- a/services/inputflinger/reader/include/InputReader.h +++ b/services/inputflinger/reader/include/InputReader.h @@ -95,6 +95,10 @@ public: void flushSensor(int32_t deviceId, InputDeviceSensorType sensorType) override; + std::optional getBatteryCapacity(int32_t deviceId) override; + + std::optional getBatteryStatus(int32_t deviceId) override; + protected: // These members are protected so they can be instrumented by test cases. virtual std::shared_ptr createDeviceLocked(int32_t deviceId, diff --git a/services/inputflinger/reader/mapper/BatteryInputMapper.cpp b/services/inputflinger/reader/mapper/BatteryInputMapper.cpp new file mode 100644 index 0000000000..afdc5abdc2 --- /dev/null +++ b/services/inputflinger/reader/mapper/BatteryInputMapper.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../Macros.h" + +#include "BatteryInputMapper.h" + +namespace android { + +BatteryInputMapper::BatteryInputMapper(InputDeviceContext& deviceContext) + : InputMapper(deviceContext) {} + +uint32_t BatteryInputMapper::getSources() { + return 0; +} + +void BatteryInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); + + info->setHasBattery(true); +} + +void BatteryInputMapper::process(const RawEvent* rawEvent) {} + +std::optional BatteryInputMapper::getBatteryCapacity() { + return getDeviceContext().getBatteryCapacity(); +} + +std::optional BatteryInputMapper::getBatteryStatus() { + return getDeviceContext().getBatteryStatus(); +} + +void BatteryInputMapper::dump(std::string& dump) { + dump += INDENT2 "Battery Input Mapper:\n"; + dump += getBatteryCapacity().has_value() + ? StringPrintf(INDENT3 "Capacity: %d\n", getBatteryCapacity().value()) + : StringPrintf(INDENT3 "Capacity: Unknown"); + + std::string status; + switch (getBatteryStatus().value_or(BATTERY_STATUS_UNKNOWN)) { + case BATTERY_STATUS_CHARGING: + status = "Charging"; + break; + case BATTERY_STATUS_DISCHARGING: + status = "Discharging"; + break; + case BATTERY_STATUS_NOT_CHARGING: + status = "Not charging"; + break; + case BATTERY_STATUS_FULL: + status = "Full"; + break; + default: + status = "Unknown"; + } + dump += StringPrintf(INDENT3 "Status: %s\n", status.c_str()); +} + +} // namespace android diff --git a/services/inputflinger/reader/mapper/BatteryInputMapper.h b/services/inputflinger/reader/mapper/BatteryInputMapper.h new file mode 100644 index 0000000000..4fe373e2ca --- /dev/null +++ b/services/inputflinger/reader/mapper/BatteryInputMapper.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _UI_INPUTREADER_BATTERY_INPUT_MAPPER_H +#define _UI_INPUTREADER_BATTERY_INPUT_MAPPER_H + +#include "InputMapper.h" + +namespace android { + +class BatteryInputMapper : public InputMapper { +public: + explicit BatteryInputMapper(InputDeviceContext& deviceContext); + virtual ~BatteryInputMapper(){}; + + uint32_t getSources() override; + void populateDeviceInfo(InputDeviceInfo* deviceInfo) override; + void process(const RawEvent* rawEvent) override; + + std::optional getBatteryCapacity() override; + std::optional getBatteryStatus() override; + + void dump(std::string& dump) override; +}; + +} // namespace android + +#endif // _UI_INPUTREADER_BATTERY_INPUT_MAPPER_H diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h index 6ca6ec9a73..44af998693 100644 --- a/services/inputflinger/reader/mapper/InputMapper.h +++ b/services/inputflinger/reader/mapper/InputMapper.h @@ -72,6 +72,9 @@ public: virtual void disableSensor(InputDeviceSensorType sensorType); virtual void flushSensor(InputDeviceSensorType sensorType); + virtual std::optional getBatteryCapacity() { return std::nullopt; } + virtual std::optional getBatteryStatus() { return std::nullopt; } + virtual int32_t getMetaState(); virtual void updateMetaState(int32_t keyCode); diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 91d5864670..19ffd65034 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include #include #include @@ -67,6 +68,8 @@ static constexpr int32_t INVALID_TRACKING_ID = -1; static constexpr int32_t FIRST_TRACKING_ID = 0; static constexpr int32_t SECOND_TRACKING_ID = 1; static constexpr int32_t THIRD_TRACKING_ID = 2; +static constexpr int32_t BATTERY_STATUS = 4; +static constexpr int32_t BATTERY_CAPACITY = 66; // Error tolerance for floating point assertions. static const float EPSILON = 0.001f; @@ -863,6 +866,10 @@ private: std::vector getVibratorIds(int32_t deviceId) override { return mVibrators; }; + std::optional getBatteryCapacity(int32_t) const override { return BATTERY_CAPACITY; } + + std::optional getBatteryStatus(int32_t) const override { return BATTERY_STATUS; } + virtual bool isExternal(int32_t) const { return false; } @@ -1924,6 +1931,52 @@ TEST_F(InputReaderTest, VibratorGetVibratorIds) { ASSERT_EQ(mReader->getVibratorIds(deviceId).size(), 2U); } +class FakeBatteryInputMapper : public FakeInputMapper { +public: + FakeBatteryInputMapper(InputDeviceContext& deviceContext, uint32_t sources) + : FakeInputMapper(deviceContext, sources) {} + + std::optional getBatteryCapacity() override { + return getDeviceContext().getBatteryCapacity(); + } + + std::optional getBatteryStatus() override { + return getDeviceContext().getBatteryStatus(); + } +}; + +TEST_F(InputReaderTest, BatteryGetCapacity) { + constexpr int32_t deviceId = END_RESERVED_ID + 1000; + Flags deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY; + constexpr int32_t eventHubId = 1; + const char* DEVICE_LOCATION = "BLUETOOTH"; + std::shared_ptr device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION); + FakeBatteryInputMapper& mapper = + device->addMapper(eventHubId, AINPUT_SOURCE_KEYBOARD); + mReader->pushNextDevice(device); + + ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr)); + ASSERT_NO_FATAL_FAILURE(mapper.assertConfigureWasCalled()); + + ASSERT_EQ(mReader->getBatteryCapacity(deviceId), BATTERY_CAPACITY); +} + +TEST_F(InputReaderTest, BatteryGetStatus) { + constexpr int32_t deviceId = END_RESERVED_ID + 1000; + Flags deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY; + constexpr int32_t eventHubId = 1; + const char* DEVICE_LOCATION = "BLUETOOTH"; + std::shared_ptr device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION); + FakeBatteryInputMapper& mapper = + device->addMapper(eventHubId, AINPUT_SOURCE_KEYBOARD); + mReader->pushNextDevice(device); + + ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr)); + ASSERT_NO_FATAL_FAILURE(mapper.assertConfigureWasCalled()); + + ASSERT_EQ(mReader->getBatteryStatus(deviceId), BATTERY_STATUS); +} + // --- InputReaderIntegrationTest --- // These tests create and interact with the InputReader only through its interface. @@ -2799,6 +2852,32 @@ TEST_F(SensorInputMapperTest, ProcessGyroscopeSensor) { mapper.flushSensor(InputDeviceSensorType::GYROSCOPE); } +// --- BatteryInputMapperTest --- +class BatteryInputMapperTest : public InputMapperTest { +protected: + void SetUp() override { InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::BATTERY); } +}; + +TEST_F(BatteryInputMapperTest, GetSources) { + BatteryInputMapper& mapper = addMapperAndConfigure(); + + ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, mapper.getSources()); +} + +TEST_F(BatteryInputMapperTest, GetBatteryCapacity) { + BatteryInputMapper& mapper = addMapperAndConfigure(); + + ASSERT_TRUE(mapper.getBatteryCapacity()); + ASSERT_EQ(*mapper.getBatteryCapacity(), BATTERY_CAPACITY); +} + +TEST_F(BatteryInputMapperTest, GetBatteryStatus) { + BatteryInputMapper& mapper = addMapperAndConfigure(); + + ASSERT_TRUE(mapper.getBatteryStatus()); + ASSERT_EQ(*mapper.getBatteryStatus(), BATTERY_STATUS); +} + // --- KeyboardInputMapperTest --- class KeyboardInputMapperTest : public InputMapperTest { -- cgit v1.2.3-59-g8ed1b From 20dcde8e35b003a82e4c14d39c76f93a16ec6e9d Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 31 Jul 2020 16:01:53 -0700 Subject: SF: use parent layer frame rate If an ancestor of a layer set a frame rate, and that layer doesn't have a frame rate configured, use the one of the ancestor. The reason for this is to support the high refresh rate deny list where WM will set the frame rate on a container layer which is not visible. With this change we will treat all child layers of that container as if they voted themselves. Test: test app that sets preferredDisplayModeId Bug: 163079696 Change-Id: I3c55d393af72e19cd7b4f107d8cc0b2e85289d96 --- services/surfaceflinger/Layer.cpp | 34 +++++++++++++--------- .../tests/unittests/SetFrameRateTest.cpp | 22 +++++++------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index a545d186dd..24d1b52a49 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1432,9 +1432,10 @@ void Layer::updateTreeHasFrameRateVote() { }; // update parents and children about the vote - // First traverse the tree and count how many layers has votes + // First traverse the tree and count how many layers has votes. In addition + // activate the layers in Scheduler's LayerHistory for it to check for changes int layersWithVote = 0; - traverseTree([&layersWithVote](Layer* layer) { + traverseTree([&layersWithVote, this](Layer* layer) { const auto layerVotedWithDefaultCompatibility = layer->mCurrentState.frameRate.rate.isValid() && layer->mCurrentState.frameRate.type == FrameRateCompatibility::Default; @@ -1447,6 +1448,9 @@ void Layer::updateTreeHasFrameRateVote() { if (layerVotedWithDefaultCompatibility || layerVotedWithNoVote) { layersWithVote++; } + + mFlinger->mScheduler->recordLayerHistory(layer, systemTime(), + LayerHistory::LayerUpdateType::SetFrameRate); }); // Now update the other layers @@ -1474,10 +1478,6 @@ bool Layer::setFrameRate(FrameRate frameRate) { return false; } - // Activate the layer in Scheduler's LayerHistory - mFlinger->mScheduler->recordLayerHistory(this, systemTime(), - LayerHistory::LayerUpdateType::SetFrameRate); - mCurrentState.sequence++; mCurrentState.frameRate = frameRate; mCurrentState.modified = true; @@ -1501,8 +1501,16 @@ Layer::FrameRate Layer::getFrameRateForLayerTree() const { return frameRate; } - // This layer doesn't have a frame rate. If one of its ancestors or successors - // have a vote, return a NoVote for ancestors/successors to set the vote + // This layer doesn't have a frame rate. Check if its ancestors have a vote + if (sp parent = getParent(); parent) { + if (const auto parentFrameRate = parent->getFrameRateForLayerTree(); + parentFrameRate.rate.isValid()) { + return parentFrameRate; + } + } + + // This layer and its ancestors don't have a frame rate. If one of successors + // has a vote, return a NoVote for successors to set the vote if (getDrawingState().treeHasFrameRateVote) { return {Fps(0.0f), FrameRateCompatibility::NoVote}; } @@ -1692,11 +1700,11 @@ void Layer::miniDump(std::string& result, const DisplayDevice& display) const { const FloatRect& crop = outputLayerState.sourceCrop; StringAppendF(&result, "%6.1f %6.1f %6.1f %6.1f | ", crop.left, crop.top, crop.right, crop.bottom); - if (layerState.frameRate.rate.isValid() || - layerState.frameRate.type != FrameRateCompatibility::Default) { - StringAppendF(&result, "%s %15s %17s", to_string(layerState.frameRate.rate).c_str(), - frameRateCompatibilityString(layerState.frameRate.type).c_str(), - toString(layerState.frameRate.seamlessness).c_str()); + const auto frameRate = getFrameRateForLayerTree(); + if (frameRate.rate.isValid() || frameRate.type != FrameRateCompatibility::Default) { + StringAppendF(&result, "%s %15s %17s", to_string(frameRate.rate).c_str(), + frameRateCompatibilityString(frameRate.type).c_str(), + toString(frameRate.seamlessness).c_str()); } else { result.append(41, ' '); } diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index 1bbe8e2485..c8f4cb4c19 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -263,13 +263,13 @@ TEST_P(SetFrameRateTest, SetAndGetParentAllVote) { commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE2, child2->getFrameRateForLayerTree()); child1->setFrameRate(FRAME_RATE_NO_VOTE); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE3, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE3, child2->getFrameRateForLayerTree()); parent->setFrameRate(FRAME_RATE_NO_VOTE); commitTransaction(); @@ -293,8 +293,8 @@ TEST_P(SetFrameRateTest, SetAndGetChild) { parent->setFrameRate(FRAME_RATE_VOTE1); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); parent->setFrameRate(FRAME_RATE_NO_VOTE); commitTransaction(); @@ -356,14 +356,14 @@ TEST_P(SetFrameRateTest, SetAndGetChildAddAfterVote) { parent->setFrameRate(FRAME_RATE_VOTE1); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); addChild(child1, child2); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); parent->setFrameRate(FRAME_RATE_NO_VOTE); commitTransaction(); @@ -387,13 +387,13 @@ TEST_P(SetFrameRateTest, SetAndGetChildRemoveAfterVote) { parent->setFrameRate(FRAME_RATE_VOTE1); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); removeChild(child1, child2); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); parent->setFrameRate(FRAME_RATE_NO_VOTE); -- cgit v1.2.3-59-g8ed1b From 35018763c0098ce802d51408f77b13633128041c Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 7 Jan 2021 17:56:08 -0800 Subject: SurfaceFlinger: handle high refresh rate deny list Add visibility to SurfaceFlinger into the high refresh rate deny list and let SurfaceFlinger handle it. Previously WM was setting the preferredDisplayModeId on the denied app's window. The old way prevented SurfaceFlinger to use the frame rate override feature as it didn't know that a specific app is causing the refresh rate spec to be limited. With this change, SurfaceFlinger will limit the display refresh rate based on the high refresh rate deny list, and if possible, will use the frame rate override feature to change the display rate to a multiple, allowing other animations to be smooth while the denied app remains in the low refresh rate. Bug: 170502573 Test: SF unit tests Change-Id: Idc8a5fe6bc12dbd949ad5e09ff50e339ffaeac36 --- libs/gui/LayerState.cpp | 10 +- libs/gui/SurfaceComposerClient.cpp | 5 +- libs/gui/include/gui/LayerState.h | 13 +- libs/nativewindow/include/apex/window.h | 13 ++ services/surfaceflinger/Layer.cpp | 9 +- services/surfaceflinger/Layer.h | 2 + services/surfaceflinger/Scheduler/LayerHistory.cpp | 3 + .../Scheduler/RefreshRateConfigs.cpp | 88 ++++++++--- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 20 ++- services/surfaceflinger/Scheduler/Scheduler.cpp | 10 +- services/surfaceflinger/SurfaceFlinger.cpp | 6 +- .../tests/unittests/RefreshRateConfigsTest.cpp | 176 +++++++++++++++++++-- .../tests/unittests/SetFrameRateTest.cpp | 15 ++ 13 files changed, 308 insertions(+), 62 deletions(-) diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 63be3edf94..e5e10a0014 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -16,6 +16,7 @@ #define LOG_TAG "LayerState" +#include #include #include @@ -620,7 +621,8 @@ status_t InputWindowCommands::read(const Parcel& input) { return NO_ERROR; } -bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunctionName) { +bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunctionName, + bool privileged) { const char* functionName = inFunctionName != nullptr ? inFunctionName : "call"; int floatClassification = std::fpclassify(frameRate); if (frameRate < 0 || floatClassification == FP_INFINITE || floatClassification == FP_NAN) { @@ -629,8 +631,10 @@ bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunc } if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT && - compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE) { - ALOGE("%s failed - invalid compatibility value %d", functionName, compatibility); + compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE && + (!privileged || compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT)) { + ALOGE("%s failed - invalid compatibility value %d privileged: %s", functionName, + compatibility, privileged ? "yes" : "no"); return false; } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 4a372bba1e..78f655a71b 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1518,7 +1518,10 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame mStatus = BAD_INDEX; return *this; } - if (!ValidateFrameRate(frameRate, compatibility, "Transaction::setFrameRate")) { + // Allow privileged values as well here, those will be ignored by SF if + // the caller is not privileged + if (!ValidateFrameRate(frameRate, compatibility, "Transaction::setFrameRate", + /*privileged=*/true)) { mStatus = BAD_VALUE; return *this; } diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 4a291aeb02..83a9d3356e 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -309,11 +309,14 @@ static inline int compare_type(const DisplayState& lhs, const DisplayState& rhs) return compare_type(lhs.token, rhs.token); } -// Returns true if the frameRate and compatibility are valid values, false -// othwerise. If either of the params are invalid, an error log is printed, and -// functionName is added to the log to indicate which function call failed. -// functionName can be null. -bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* functionName); +// Returns true if the frameRate is valid. +// +// @param frameRate the frame rate in Hz +// @param compatibility a ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* +// @param functionName calling function or nullptr. Used for logging +// @param privileged whether caller has unscoped surfaceflinger access +bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* functionName, + bool privileged = false); struct CaptureArgs { const static int32_t UNSET_UID = -1; diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h index 2d1354cdf1..0923438eec 100644 --- a/libs/nativewindow/include/apex/window.h +++ b/libs/nativewindow/include/apex/window.h @@ -39,6 +39,19 @@ enum ANativeWindowPerform { // clang-format on }; +/* + * Internal extension of compatibility value for ANativeWindow_setFrameRate. */ +enum ANativeWindow_FrameRateCompatibilityInternal { + /** + * This surface belongs to an app on the High Refresh Rate Deny list, and needs the display + * to operate at the exact frame rate. + * + * This is used internally by the platform and should not be used by apps. + * @hide + */ + ANATIVEWINDOW_FRAME_RATE_EXACT = 100, +}; + /** * Prototype of the function that an ANativeWindow implementation would call * when ANativeWindow_cancelBuffer is called. diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 24d1b52a49..66ce3f1a44 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1441,11 +1441,14 @@ void Layer::updateTreeHasFrameRateVote() { layer->mCurrentState.frameRate.type == FrameRateCompatibility::Default; const auto layerVotedWithNoVote = layer->mCurrentState.frameRate.type == FrameRateCompatibility::NoVote; + const auto layerVotedWithExactCompatibility = + layer->mCurrentState.frameRate.type == FrameRateCompatibility::Exact; // We do not count layers that are ExactOrMultiple for the same reason // we are allowing touch boost for those layers. See // RefreshRateConfigs::getBestRefreshRate for more details. - if (layerVotedWithDefaultCompatibility || layerVotedWithNoVote) { + if (layerVotedWithDefaultCompatibility || layerVotedWithNoVote || + layerVotedWithExactCompatibility) { layersWithVote++; } @@ -1662,6 +1665,8 @@ std::string Layer::frameRateCompatibilityString(Layer::FrameRateCompatibility co return "ExactOrMultiple"; case FrameRateCompatibility::NoVote: return "NoVote"; + case FrameRateCompatibility::Exact: + return "Exact"; } } @@ -2763,6 +2768,8 @@ Layer::FrameRateCompatibility Layer::FrameRate::convertCompatibility(int8_t comp return FrameRateCompatibility::Default; case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE: return FrameRateCompatibility::ExactOrMultiple; + case ANATIVEWINDOW_FRAME_RATE_EXACT: + return FrameRateCompatibility::Exact; default: LOG_ALWAYS_FATAL("Invalid frame rate compatibility value %d", compatibility); return FrameRateCompatibility::Default; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index f78b5f31e9..359340eb64 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -145,6 +145,8 @@ public: enum class FrameRateCompatibility { Default, // Layer didn't specify any specific handling strategy + Exact, // Layer needs the exact frame rate. + ExactOrMultiple, // Layer needs the exact frame rate (or a multiple of it) to present the // content properly. Any other value will result in a pull down. diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 170933d9b3..7ef531df63 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -71,6 +71,7 @@ void trace(const wp& weak, const LayerInfo& info, LayerHistory::LayerVote traceType(LayerHistory::LayerVoteType::Heuristic, fps); traceType(LayerHistory::LayerVoteType::ExplicitDefault, fps); traceType(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, fps); + traceType(LayerHistory::LayerVoteType::ExplicitExact, fps); traceType(LayerHistory::LayerVoteType::Min, 1); traceType(LayerHistory::LayerVoteType::Max, 1); @@ -172,6 +173,8 @@ void LayerHistory::partitionLayers(nsecs_t now) { return LayerVoteType::ExplicitExactOrMultiple; case Layer::FrameRateCompatibility::NoVote: return LayerVoteType::NoVote; + case Layer::FrameRateCompatibility::Exact: + return LayerVoteType::ExplicitExact; } }(); diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 0f1e26750e..81ffe0f20e 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -83,6 +83,8 @@ std::string RefreshRateConfigs::layerVoteTypeString(LayerVoteType vote) { return "ExplicitDefault"; case LayerVoteType::ExplicitExactOrMultiple: return "ExplicitExactOrMultiple"; + case LayerVoteType::ExplicitExact: + return "ExplicitExact"; } } @@ -165,6 +167,18 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye return (1.0f / iter) * seamlessness; } + if (layer.vote == LayerVoteType::ExplicitExact) { + const int divider = getFrameRateDivider(refreshRate.getFps(), layer.desiredRefreshRate); + if (mSupportsFrameRateOverride) { + // Since we support frame rate override, allow refresh rates which are + // multiples of the layer's request, as those apps would be throttled + // down to run at the desired refresh rate. + return divider > 0; + } + + return divider == 1; + } + return 0; } @@ -199,21 +213,34 @@ RefreshRate RefreshRateConfigs::getBestRefreshRate(const std::vector 0 || explicitExactOrMultipleVoteLayers > 0; + const bool hasExplicitVoteLayers = explicitDefaultVoteLayers > 0 || + explicitExactOrMultipleVoteLayers > 0 || explicitExact > 0; // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've // selected a refresh rate to see if we should apply touch boost. @@ -318,7 +345,9 @@ RefreshRate RefreshRateConfigs::getBestRefreshRate(const std::vectorinPolicy(policy->primaryRange.min, policy->primaryRange.max); if ((primaryRangeIsSingleRate || !inPrimaryRange) && - !(layer.focused && layer.vote == LayerVoteType::ExplicitDefault)) { + !(layer.focused && + (layer.vote == LayerVoteType::ExplicitDefault || + layer.vote == LayerVoteType::ExplicitExact))) { // Only focused layers with ExplicitDefault frame rate settings are allowed to score // refresh rates outside the primary range. continue; @@ -358,7 +387,8 @@ RefreshRate RefreshRateConfigs::getBestRefreshRate(const std::vectorfps.lessThanWithMargin(touchRefreshRate.fps)) { setTouchConsidered(); ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str()); @@ -412,7 +442,7 @@ std::vector initializeScoresForAllRefreshRates( } RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverrides( - const std::vector& layers, Fps displayFrameRate) const { + const std::vector& layers, Fps displayFrameRate, bool touch) const { ATRACE_CALL(); if (!mSupportsFrameRateOverride) return {}; @@ -423,6 +453,17 @@ RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverr groupLayersByUid(layers); UidToFrameRateOverride frameRateOverrides; for (const auto& [uid, layersWithSameUid] : layersByUid) { + // Layers with ExplicitExactOrMultiple expect touch boost + const bool hasExplicitExactOrMultiple = + std::any_of(layersWithSameUid.cbegin(), layersWithSameUid.cend(), + [](const auto& layer) { + return layer->vote == LayerVoteType::ExplicitExactOrMultiple; + }); + + if (touch && hasExplicitExactOrMultiple) { + continue; + } + for (auto& score : scores) { score.score = 0; } @@ -433,7 +474,8 @@ RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverr } LOG_ALWAYS_FATAL_IF(layer->vote != LayerVoteType::ExplicitDefault && - layer->vote != LayerVoteType::ExplicitExactOrMultiple); + layer->vote != LayerVoteType::ExplicitExactOrMultiple && + layer->vote != LayerVoteType::ExplicitExact); for (RefreshRateScore& score : scores) { const auto layerScore = calculateLayerScoreLocked(*layer, *score.refreshRate, /*isSeamlessSwitch*/ true); @@ -559,8 +601,10 @@ void RefreshRateConfigs::setCurrentConfigId(DisplayModeId configId) { mCurrentRefreshRate = mRefreshRates.at(configId).get(); } -RefreshRateConfigs::RefreshRateConfigs(const DisplayModes& configs, DisplayModeId currentConfigId) - : mKnownFrameRates(constructKnownFrameRates(configs)) { +RefreshRateConfigs::RefreshRateConfigs(const DisplayModes& configs, DisplayModeId currentConfigId, + bool enableFrameRateOverride) + : mKnownFrameRates(constructKnownFrameRates(configs)), + mEnableFrameRateOverride(enableFrameRateOverride) { updateDisplayConfigs(configs, currentConfigId); } @@ -589,7 +633,7 @@ void RefreshRateConfigs::updateDisplayConfigs(const DisplayModes& configs, mMaxSupportedRefreshRate = sortedConfigs.back(); mSupportsFrameRateOverride = false; - if (android::sysprop::enable_frame_rate_override(true)) { + if (mEnableFrameRateOverride) { for (const auto& config1 : sortedConfigs) { for (const auto& config2 : sortedConfigs) { if (getFrameRateDivider(config1->getFps(), config2->getFps()) >= 2) { @@ -826,4 +870,4 @@ void RefreshRateConfigs::dump(std::string& result) const { } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file +#pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index ef193ca787..36fbbad4d8 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -208,8 +208,11 @@ public: Heuristic, // Specific refresh rate that was calculated by platform using a heuristic ExplicitDefault, // Specific refresh rate that was provided by the app with Default // compatibility - ExplicitExactOrMultiple // Specific refresh rate that was provided by the app with - // ExactOrMultiple compatibility + ExplicitExactOrMultiple, // Specific refresh rate that was provided by the app with + // ExactOrMultiple compatibility + ExplicitExact, // Specific refresh rate that was provided by the app with + // Exact compatibility + }; // Captures the layer requirements for a refresh rate. This will be used to determine the @@ -295,7 +298,8 @@ public: // Returns a known frame rate that is the closest to frameRate Fps findClosestKnownFrameRate(Fps frameRate) const; - RefreshRateConfigs(const DisplayModes& configs, DisplayModeId currentConfigId); + RefreshRateConfigs(const DisplayModes& configs, DisplayModeId currentConfigId, + bool enableFrameRateOverride = false); void updateDisplayConfigs(const DisplayModes& configs, DisplayModeId currentConfig) EXCLUDES(mLock); @@ -324,10 +328,15 @@ public: // Returns a divider for the current refresh rate int getRefreshRateDivider(Fps frameRate) const EXCLUDES(mLock); - // Returns the frame rate override for each uid using UidToFrameRateOverride = std::map; + // Returns the frame rate override for each uid. + // + // @param layers list of visible layers + // @param displayFrameRate the display frame rate + // @param touch whether touch timer is active (i.e. user touched the screen recently) UidToFrameRateOverride getFrameRateOverrides(const std::vector& layers, - Fps displayFrameRate) const EXCLUDES(mLock); + Fps displayFrameRate, bool touch) const + EXCLUDES(mLock); void dump(std::string& result) const EXCLUDES(mLock); @@ -407,6 +416,7 @@ private: // from based on the closest value. const std::vector mKnownFrameRates; + const bool mEnableFrameRateOverride; bool mSupportsFrameRateOverride; }; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 588b83d774..d8612098ec 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -763,17 +763,11 @@ bool Scheduler::updateFrameRateOverrides( return false; } - if (consideredSignals.touch) { - std::lock_guard lock(mFrameRateOverridesMutex); - const bool changed = !mFrameRateOverridesByContent.empty(); - mFrameRateOverridesByContent.clear(); - return changed; - } - if (!consideredSignals.idle) { const auto frameRateOverrides = mRefreshRateConfigs.getFrameRateOverrides(mFeatures.contentRequirements, - displayRefreshRate); + displayRefreshRate, + consideredSignals.touch); std::lock_guard lock(mFrameRateOverridesMutex); if (!std::equal(mFrameRateOverridesByContent.begin(), mFrameRateOverridesByContent.end(), frameRateOverrides.begin(), frameRateOverrides.end(), diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 0a51659681..c1fabf8322 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2920,7 +2920,9 @@ void SurfaceFlinger::initScheduler(PhysicalDisplayId primaryDisplayId) { auto currentConfig = getHwComposer().getActiveMode(primaryDisplayId)->getId(); const auto modes = getHwComposer().getModes(primaryDisplayId); - mRefreshRateConfigs = std::make_unique(modes, currentConfig); + mRefreshRateConfigs = std::make_unique< + scheduler::RefreshRateConfigs>(modes, currentConfig, + android::sysprop::enable_frame_rate_override(true)); const auto& currRefreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(currentConfig); mRefreshRateStats = std::make_unique(*mTimeStats, currRefreshRate.getFps(), @@ -3873,7 +3875,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( } if (what & layer_state_t::eFrameRateChanged) { if (ValidateFrameRate(s.frameRate, s.frameRateCompatibility, - "SurfaceFlinger::setClientStateLocked") && + "SurfaceFlinger::setClientStateLocked", privileged) && layer->setFrameRate(Layer::FrameRate(Fps(s.frameRate), Layer::FrameRate::convertCompatibility( s.frameRateCompatibility), diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 0a747ab7e3..738ded18ac 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -1506,6 +1506,89 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_KnownFrameRate) { } } +TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExact) { + auto refreshRateConfigs = + std::make_unique(m30_60_72_90_120Device, + /*currentConfigId=*/HWC_CONFIG_ID_60); + + auto layers = std::vector{LayerRequirement{.weight = 1.0f}, + LayerRequirement{.weight = 0.5f}}; + auto& explicitExactLayer = layers[0]; + auto& explicitExactOrMultipleLayer = layers[1]; + + explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple; + explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple"; + explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60); + + explicitExactLayer.vote = LayerVoteType::ExplicitExact; + explicitExactLayer.name = "ExplicitExact"; + explicitExactLayer.desiredRefreshRate = Fps(30); + + EXPECT_EQ(mExpected30Config, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected30Config, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false})); + + explicitExactOrMultipleLayer.desiredRefreshRate = Fps(120); + explicitExactLayer.desiredRefreshRate = Fps(60); + EXPECT_EQ(mExpected60Config, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + + explicitExactLayer.desiredRefreshRate = Fps(72); + EXPECT_EQ(mExpected72Config, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + + explicitExactLayer.desiredRefreshRate = Fps(90); + EXPECT_EQ(mExpected90Config, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + + explicitExactLayer.desiredRefreshRate = Fps(120); + EXPECT_EQ(mExpected120Config, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); +} + +TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExactEnableFrameRateOverride) { + auto refreshRateConfigs = + std::make_unique(m30_60_72_90_120Device, + /*currentConfigId=*/HWC_CONFIG_ID_60, + /*enableFrameRateOverride=*/true); + + auto layers = std::vector{LayerRequirement{.weight = 1.0f}, + LayerRequirement{.weight = 0.5f}}; + auto& explicitExactLayer = layers[0]; + auto& explicitExactOrMultipleLayer = layers[1]; + + explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple; + explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple"; + explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60); + + explicitExactLayer.vote = LayerVoteType::ExplicitExact; + explicitExactLayer.name = "ExplicitExact"; + explicitExactLayer.desiredRefreshRate = Fps(30); + + EXPECT_EQ(mExpected60Config, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected120Config, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false})); + + explicitExactOrMultipleLayer.desiredRefreshRate = Fps(120); + explicitExactLayer.desiredRefreshRate = Fps(60); + EXPECT_EQ(mExpected120Config, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + + explicitExactLayer.desiredRefreshRate = Fps(72); + EXPECT_EQ(mExpected72Config, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + + explicitExactLayer.desiredRefreshRate = Fps(90); + EXPECT_EQ(mExpected90Config, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + + explicitExactLayer.desiredRefreshRate = Fps(120); + EXPECT_EQ(mExpected120Config, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); +} + TEST_F(RefreshRateConfigsTest, testComparisonOperator) { EXPECT_TRUE(mExpected60Config < mExpected90Config); EXPECT_FALSE(mExpected60Config < mExpected60Config); @@ -1537,7 +1620,7 @@ TEST_F(RefreshRateConfigsTest, testKernelIdleTimerAction) { EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction()); } -TEST_F(RefreshRateConfigsTest, RefreshRateDividerForUid) { +TEST_F(RefreshRateConfigsTest, getRefreshRateDivider) { auto refreshRateConfigs = std::make_unique(m30_60_72_90_120Device, /*currentConfigId=*/HWC_CONFIG_ID_30); @@ -1562,57 +1645,66 @@ TEST_F(RefreshRateConfigsTest, RefreshRateDividerForUid) { EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDivider(Fps(22.6f))); } -TEST_F(RefreshRateConfigsTest, populatePreferredFrameRate_noLayers) { +TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_noLayers) { auto refreshRateConfigs = std::make_unique(m30_60_72_90_120Device, /*currentConfigId=*/ HWC_CONFIG_ID_120); auto layers = std::vector{}; - ASSERT_TRUE(refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f)).empty()); + ASSERT_TRUE(refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false) + .empty()); } TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_60on120) { auto refreshRateConfigs = std::make_unique(m30_60_72_90_120Device, /*currentConfigId=*/ - HWC_CONFIG_ID_120); + HWC_CONFIG_ID_120, + /*enableFrameRateOverride=*/true); auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; layers[0].name = "Test layer"; layers[0].ownerUid = 1234; layers[0].desiredRefreshRate = Fps(60.0f); layers[0].vote = LayerVoteType::ExplicitDefault; - auto frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f)); + auto frameRateOverrides = + refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); ASSERT_EQ(1, frameRateOverrides.size()); ASSERT_EQ(1, frameRateOverrides.count(1234)); ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue()); layers[0].vote = LayerVoteType::ExplicitExactOrMultiple; - frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f)); + frameRateOverrides = + refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); ASSERT_EQ(1, frameRateOverrides.size()); ASSERT_EQ(1, frameRateOverrides.count(1234)); ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue()); layers[0].vote = LayerVoteType::NoVote; - frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f)); + frameRateOverrides = + refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); ASSERT_TRUE(frameRateOverrides.empty()); layers[0].vote = LayerVoteType::Min; - frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f)); + frameRateOverrides = + refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); ASSERT_TRUE(frameRateOverrides.empty()); layers[0].vote = LayerVoteType::Max; - frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f)); + frameRateOverrides = + refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); ASSERT_TRUE(frameRateOverrides.empty()); layers[0].vote = LayerVoteType::Heuristic; - frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f)); + frameRateOverrides = + refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); ASSERT_TRUE(frameRateOverrides.empty()); } -TEST_F(RefreshRateConfigsTest, populatePreferredFrameRate_twoUids) { +TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_twoUids) { auto refreshRateConfigs = std::make_unique(m30_60_72_90_120Device, /*currentConfigId=*/ - HWC_CONFIG_ID_120); + HWC_CONFIG_ID_120, + /*enableFrameRateOverride=*/true); auto layers = std::vector{ LayerRequirement{.ownerUid = 1234, .weight = 1.0f}, @@ -1626,7 +1718,8 @@ TEST_F(RefreshRateConfigsTest, populatePreferredFrameRate_twoUids) { layers[1].name = "Test layer 5678"; layers[1].desiredRefreshRate = Fps(30.0f); layers[1].vote = LayerVoteType::ExplicitDefault; - auto frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f)); + auto frameRateOverrides = + refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); ASSERT_EQ(2, frameRateOverrides.size()); ASSERT_EQ(1, frameRateOverrides.count(1234)); @@ -1635,13 +1728,66 @@ TEST_F(RefreshRateConfigsTest, populatePreferredFrameRate_twoUids) { ASSERT_EQ(30.0f, frameRateOverrides.at(5678).getValue()); layers[1].vote = LayerVoteType::Heuristic; - frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f)); + frameRateOverrides = + refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); ASSERT_EQ(1, frameRateOverrides.size()); ASSERT_EQ(1, frameRateOverrides.count(1234)); ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue()); layers[1].ownerUid = 1234; - frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f)); + frameRateOverrides = + refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); + ASSERT_TRUE(frameRateOverrides.empty()); +} + +TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_touch) { + auto refreshRateConfigs = + std::make_unique(m30_60_72_90_120Device, /*currentConfigId=*/ + HWC_CONFIG_ID_120, + /*enableFrameRateOverride=*/true); + + auto layers = std::vector{ + LayerRequirement{.ownerUid = 1234, .weight = 1.0f}, + }; + + layers[0].name = "Test layer"; + layers[0].desiredRefreshRate = Fps(60.0f); + layers[0].vote = LayerVoteType::ExplicitDefault; + + auto frameRateOverrides = + refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); + ASSERT_EQ(1, frameRateOverrides.size()); + ASSERT_EQ(1, frameRateOverrides.count(1234)); + ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue()); + + frameRateOverrides = + refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/true); + ASSERT_EQ(1, frameRateOverrides.size()); + ASSERT_EQ(1, frameRateOverrides.count(1234)); + ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue()); + + layers[0].vote = LayerVoteType::ExplicitExact; + frameRateOverrides = + refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); + ASSERT_EQ(1, frameRateOverrides.size()); + ASSERT_EQ(1, frameRateOverrides.count(1234)); + ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue()); + + frameRateOverrides = + refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/true); + ASSERT_EQ(1, frameRateOverrides.size()); + ASSERT_EQ(1, frameRateOverrides.count(1234)); + ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue()); + + layers[0].vote = LayerVoteType::ExplicitExactOrMultiple; + frameRateOverrides = + refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); + ASSERT_EQ(1, frameRateOverrides.size()); + ASSERT_EQ(1, frameRateOverrides.count(1234)); + ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue()); + + frameRateOverrides = + refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/true); ASSERT_TRUE(frameRateOverrides.empty()); } diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index c8f4cb4c19..e060df2420 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -473,5 +473,20 @@ INSTANTIATE_TEST_SUITE_P(PerLayerType, SetFrameRateTest, std::make_shared()), PrintToStringParamName); +TEST_F(SetFrameRateTest, ValidateFrameRate) { + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, "")); + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, "")); + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, "")); + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, "", /*privileged=*/true)); + + EXPECT_FALSE(ValidateFrameRate(-1, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, "")); + EXPECT_FALSE( + ValidateFrameRate(1.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, "")); + EXPECT_FALSE( + ValidateFrameRate(0.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, "")); + + EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, "")); +} + } // namespace } // namespace android -- cgit v1.2.3-59-g8ed1b From 652190e21dade0f7e0df01a534acf02d15f85a5f Mon Sep 17 00:00:00 2001 From: Ana Krulec Date: Mon, 25 Jan 2021 18:18:27 -0800 Subject: Increase tolerance for ChildLayerTest, ChildLayerAlpha Test currently fails on Skia. Increasing the tolerance will let the test pass while we figure out where is the discrepancy. Capturing a Skia Debug trace shows that the screen received pixels of the right color, but the screenshot that the test sees does not. Last frame at (0,0): https://screenshot.googleplex.com/4Z4AJVdzaTzpEKE Frame 6 at (0,0): https://screenshot.googleplex.com/AUyKFRzZf68KxPM Test: set RE backend to "skiaglthreaded" adb shell /data/nativetest64/SurfaceFlinger_test/SurfaceFlinger_test --gtest_filter=ChildLayerTest.ChildLayerAlpha Bug: 175352694 Change-Id: I90370ac12ad7c5f734c1f9b34b837d222c428e7b --- services/surfaceflinger/tests/LayerUpdate_test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp index 29473f20a4..806f814cf2 100644 --- a/services/surfaceflinger/tests/LayerUpdate_test.cpp +++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp @@ -450,16 +450,16 @@ TEST_F(ChildLayerTest, ChildLayerAlpha) { { mCapture = screenshot(); - // Child and BG blended. - mCapture->checkPixel(0, 0, 127, 127, 0); + // Child and BG blended. See b/175352694 for tolerance. + mCapture->expectColor(Rect(0, 0, 1, 1), Color{127, 127, 0, 255}, 1); } asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 0.5); }); { mCapture = screenshot(); - // Child and BG blended. - mCapture->checkPixel(0, 0, 95, 64, 95); + // Child and BG blended. See b/175352694 for tolerance. + mCapture->expectColor(Rect(0, 0, 1, 1), Color{95, 64, 95, 255}, 1); } } -- cgit v1.2.3-59-g8ed1b From 956c5df188cc94b1f578f6fb91ebd467d93ea459 Mon Sep 17 00:00:00 2001 From: Chris Ye Date: Tue, 26 Jan 2021 13:21:01 -0800 Subject: Update SOURCE_SENSOR source for input device. Update the SOURCE_SENSOR input source to not limited to Joystick deivce class. Bug: 170131554 Test: atest InputDeviceSensorManagerTest Change-Id: I08cb72f22d9a06f63139317551c821fd5eaa3e46 --- include/android/input.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/android/input.h b/include/android/input.h index b5d399ee09..b70d42427d 100644 --- a/include/android/input.h +++ b/include/android/input.h @@ -856,8 +856,10 @@ enum { AINPUT_SOURCE_TOUCH_NAVIGATION = 0x00200000 | AINPUT_SOURCE_CLASS_NONE, /** joystick */ AINPUT_SOURCE_JOYSTICK = 0x01000000 | AINPUT_SOURCE_CLASS_JOYSTICK, + /** HDMI */ + AINPUT_SOURCE_HDMI = 0x02000000 | AINPUT_SOURCE_CLASS_BUTTON, /** sensor */ - AINPUT_SOURCE_SENSOR = 0x02000000 | AINPUT_SOURCE_CLASS_JOYSTICK, + AINPUT_SOURCE_SENSOR = 0x04000000 | AINPUT_SOURCE_UNKNOWN, /** rotary encoder */ AINPUT_SOURCE_ROTARY_ENCODER = 0x00400000 | AINPUT_SOURCE_CLASS_NONE, -- cgit v1.2.3-59-g8ed1b From b483d52743474d50c187cfe6af359a7664c3b701 Mon Sep 17 00:00:00 2001 From: Ana Krulec Date: Wed, 27 Jan 2021 16:49:51 -0800 Subject: Adding SkiaGL RE information to dumpsys Test: adb shell dumpsys SurfaceFlinger Bug: 178539829 Change-Id: I46f016c055d73d073468785b1e67d848fd1b81ac --- libs/renderengine/skia/SkiaGLRenderEngine.cpp | 51 +++++++++++++++++++++++++++ libs/renderengine/skia/SkiaGLRenderEngine.h | 2 +- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index 79505bac20..dd26b17eb4 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -33,9 +33,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -59,6 +61,8 @@ namespace android { namespace renderengine { namespace skia { +using base::StringAppendF; + static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute, EGLint wanted, EGLConfig* outConfig) { EGLint numConfigs = -1, n = 0; @@ -1075,6 +1079,53 @@ int SkiaGLRenderEngine::getContextPriority() { return value; } +void SkiaGLRenderEngine::dump(std::string& result) { + const gl::GLExtensions& extensions = gl::GLExtensions::getInstance(); + + StringAppendF(&result, "\n ------------RE-----------------\n"); + StringAppendF(&result, "EGL implementation : %s\n", extensions.getEGLVersion()); + StringAppendF(&result, "%s\n", extensions.getEGLExtensions()); + StringAppendF(&result, "GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(), + extensions.getVersion()); + StringAppendF(&result, "%s\n", extensions.getExtensions()); + StringAppendF(&result, "RenderEngine supports protected context: %d\n", + supportsProtectedContent()); + StringAppendF(&result, "RenderEngine is in protected context: %d\n", mInProtectedContext); + + { + std::lock_guard lock(mRenderingMutex); + StringAppendF(&result, "RenderEngine texture cache size: %zu\n", mTextureCache.size()); + StringAppendF(&result, "Dumping buffer ids...\n"); + // TODO(178539829): It would be nice to know which layer these are coming from and what + // the texture sizes are. + for (const auto& [id, unused] : mTextureCache) { + StringAppendF(&result, "- 0x%" PRIx64 "\n", id); + } + StringAppendF(&result, "\n"); + StringAppendF(&result, "RenderEngine protected texture cache size: %zu\n", + mProtectedTextureCache.size()); + StringAppendF(&result, "Dumping buffer ids...\n"); + for (const auto& [id, unused] : mProtectedTextureCache) { + StringAppendF(&result, "- 0x%" PRIx64 "\n", id); + } + StringAppendF(&result, "\n"); + StringAppendF(&result, "RenderEngine runtime effects: %zu\n", mRuntimeEffects.size()); + for (const auto& [linearEffect, unused] : mRuntimeEffects) { + StringAppendF(&result, "- inputDataspace: %s\n", + dataspaceDetails( + static_cast(linearEffect.inputDataspace)) + .c_str()); + StringAppendF(&result, "- outputDataspace: %s\n", + dataspaceDetails( + static_cast(linearEffect.outputDataspace)) + .c_str()); + StringAppendF(&result, "undoPremultipliedAlpha: %s\n", + linearEffect.undoPremultipliedAlpha ? "true" : "false"); + } + } + StringAppendF(&result, "\n"); +} + } // namespace skia } // namespace renderengine } // namespace android diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index 3294de8f52..810fc2ae8f 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -63,7 +63,7 @@ public: bool useProtectedContext(bool useProtectedContext) override; protected: - void dump(std::string& /*result*/) override{}; + void dump(std::string& result) override; size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; -- cgit v1.2.3-59-g8ed1b From 58ca29d421dbec323e7f854ee8226b2d365c00be Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 13 Jan 2021 10:28:00 -1000 Subject: Add inputEventId to SurfaceFrame SurfaceFrame will now be aware of the id of the input event that caused the current frame. The flow of input event id is inputflinger -> app -> surfaceflinger. Here, we are adding the 'inputEventId' parameter to the 'setFrameTimelineVsync' call. This call will now be responsible for setting two pieces of information: the vsync id, and the input event id. Since it will no longer be limited to the vsync id, we rename this call to "setFrameTimelineInfo". Once the inputEventId is stored in SurfaceFrame, we will add a binder call to send the frame timing information to inputflinger (separate, future CL). This will allow input to reconstruct the entire sequence of events (at what time was input event getting processed in system_server, app, and surfaceflinger) and will provide the ability to measure end-to-end touch latency. In a separate change, we will also add ATRACE calls to allow manual / script-based latency analysis for local debugging. We will now know which input event is being processed in surfaceflinger. Bug: 169866723 Bug: 129481165 Design doc: https://docs.google.com/document/d/1G3bLaZYSmbe6AKcL-6ZChvrw_B_LXEz29Z6Ed9QoYXY/edit# Test: atest WMShellUnitTests SurfaceParcelable_test libgui_test IPC_test SurfaceFlinger_test Change-Id: If7e0eee82603b38b396b53ad7ced660973efcb50 --- libs/gui/Android.bp | 3 + libs/gui/BLASTBufferQueue.cpp | 14 +- libs/gui/FrameTimelineInfo.cpp | 62 +++++ libs/gui/ISurfaceComposer.cpp | 251 ++++++++++----------- libs/gui/ITransactionCompletedListener.cpp | 6 +- libs/gui/LayerState.cpp | 18 +- libs/gui/Surface.cpp | 16 +- libs/gui/SurfaceComposerClient.cpp | 41 ++-- libs/gui/include/gui/BLASTBufferQueue.h | 4 +- libs/gui/include/gui/DisplayEventDispatcher.h | 2 +- libs/gui/include/gui/FrameTimelineInfo.h | 43 ++++ libs/gui/include/gui/ISurfaceComposer.h | 14 +- libs/gui/include/gui/LayerState.h | 4 +- libs/gui/include/gui/Surface.h | 5 +- libs/gui/include/gui/SurfaceComposerClient.h | 13 +- libs/gui/tests/Surface_test.cpp | 6 +- libs/input/android/os/IInputConstants.aidl | 6 + libs/nativewindow/include/system/window.h | 11 +- services/surfaceflinger/BufferQueueLayer.cpp | 14 +- services/surfaceflinger/BufferQueueLayer.h | 6 +- .../surfaceflinger/FrameTimeline/FrameTimeline.cpp | 97 ++++---- .../surfaceflinger/FrameTimeline/FrameTimeline.h | 28 +-- services/surfaceflinger/Layer.cpp | 18 +- services/surfaceflinger/Layer.h | 9 +- services/surfaceflinger/SurfaceFlinger.cpp | 40 ++-- services/surfaceflinger/SurfaceFlinger.h | 18 +- services/surfaceflinger/tests/LayerState_test.cpp | 29 +++ .../tests/unittests/FrameTimelineTest.cpp | 187 +++++++-------- .../tests/unittests/TestableSurfaceFlinger.h | 18 +- .../tests/unittests/TransactionApplicationTest.cpp | 72 +++--- 30 files changed, 587 insertions(+), 468 deletions(-) create mode 100644 libs/gui/FrameTimelineInfo.cpp create mode 100644 libs/gui/include/gui/FrameTimelineInfo.h diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 38ae353a68..fa5044cc16 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -49,6 +49,7 @@ cc_library_shared { srcs: [ ":framework_native_aidl", + ":inputconstants_aidl", ":libgui_aidl", ":libgui_bufferqueue_sources", @@ -62,6 +63,7 @@ cc_library_shared { "DebugEGLImageTracker.cpp", "DisplayEventDispatcher.cpp", "DisplayEventReceiver.cpp", + "FrameTimelineInfo.cpp", "GLConsumer.cpp", "IConsumerListener.cpp", "IDisplayEventConnection.cpp", @@ -154,6 +156,7 @@ cc_library_static { defaults: ["libgui_bufferqueue-defaults"], srcs: [ + ":inputconstants_aidl", ":libgui_aidl", ":libgui_bufferqueue_sources", ], diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 0a3d44d336..adc7745e06 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -353,9 +353,9 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { } t->setFrameNumber(mSurfaceControl, bufferItem.mFrameNumber); - if (!mNextFrameTimelineVsyncIdQueue.empty()) { - t->setFrameTimelineVsync(mSurfaceControl, mNextFrameTimelineVsyncIdQueue.front()); - mNextFrameTimelineVsyncIdQueue.pop(); + if (!mNextFrameTimelineInfoQueue.empty()) { + t->setFrameTimelineInfo(mSurfaceControl, mNextFrameTimelineInfoQueue.front()); + mNextFrameTimelineInfoQueue.pop(); } if (mAutoRefresh != bufferItem.mAutoRefresh) { @@ -514,8 +514,8 @@ public: return mBbq->setFrameRate(frameRate, compatibility, shouldBeSeamless); } - status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId) override { - return mBbq->setFrameTimelineVsync(frameTimelineVsyncId); + status_t setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) override { + return mBbq->setFrameTimelineInfo(frameTimelineInfo); } }; @@ -529,9 +529,9 @@ status_t BLASTBufferQueue::setFrameRate(float frameRate, int8_t compatibility, return t.setFrameRate(mSurfaceControl, frameRate, compatibility, shouldBeSeamless).apply(); } -status_t BLASTBufferQueue::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { +status_t BLASTBufferQueue::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) { std::unique_lock _lock{mMutex}; - mNextFrameTimelineVsyncIdQueue.push(frameTimelineVsyncId); + mNextFrameTimelineInfoQueue.push(frameTimelineInfo); return OK; } diff --git a/libs/gui/FrameTimelineInfo.cpp b/libs/gui/FrameTimelineInfo.cpp new file mode 100644 index 0000000000..f40077403a --- /dev/null +++ b/libs/gui/FrameTimelineInfo.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "FrameTimelineInfo" + +#include + +#include +#include +#include +#include + +#include + +using android::os::IInputConstants; + +namespace android { + +status_t FrameTimelineInfo::write(Parcel& output) const { + SAFE_PARCEL(output.writeInt64, vsyncId); + SAFE_PARCEL(output.writeInt32, inputEventId); + return NO_ERROR; +} + +status_t FrameTimelineInfo::read(const Parcel& input) { + SAFE_PARCEL(input.readInt64, &vsyncId); + SAFE_PARCEL(input.readInt32, &inputEventId); + return NO_ERROR; +} + +void FrameTimelineInfo::merge(const FrameTimelineInfo& other) { + // When merging vsync Ids we take the oldest valid one + if (vsyncId != INVALID_VSYNC_ID && other.vsyncId != INVALID_VSYNC_ID) { + if (other.vsyncId > vsyncId) { + vsyncId = other.vsyncId; + inputEventId = other.inputEventId; + } + } else if (vsyncId == INVALID_VSYNC_ID) { + vsyncId = other.vsyncId; + inputEventId = other.inputEventId; + } +} + +void FrameTimelineInfo::clear() { + vsyncId = INVALID_VSYNC_ID; + inputEventId = IInputConstants::INVALID_INPUT_EVENT_ID; +} + +}; // namespace android diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index a8d6832275..f68f3e134e 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -68,16 +68,19 @@ public: return interface_cast(reply.readStrongBinder()); } - virtual status_t setTransactionState( - int64_t frameTimelineVsyncId, const Vector& state, - const Vector& displays, uint32_t flags, const sp& applyToken, - const InputWindowCommands& commands, int64_t desiredPresentTime, bool isAutoTimestamp, - const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, - const std::vector& listenerCallbacks, uint64_t transactionId) { + status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo, + const Vector& state, + const Vector& displays, uint32_t flags, + const sp& applyToken, const InputWindowCommands& commands, + int64_t desiredPresentTime, bool isAutoTimestamp, + const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, + const std::vector& listenerCallbacks, + uint64_t transactionId) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeInt64, frameTimelineVsyncId); + SAFE_PARCEL(frameTimelineInfo.write, data); + SAFE_PARCEL(data.writeUint32, static_cast(state.size())); for (const auto& s : state) { SAFE_PARCEL(s.write, data); @@ -108,15 +111,14 @@ public: return remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply); } - virtual void bootFinished() - { + void bootFinished() override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply); } - virtual status_t captureDisplay(const DisplayCaptureArgs& args, - const sp& captureListener) { + status_t captureDisplay(const DisplayCaptureArgs& args, + const sp& captureListener) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); SAFE_PARCEL(args.write, data); @@ -125,8 +127,8 @@ public: return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY, data, &reply); } - virtual status_t captureDisplay(uint64_t displayOrLayerStack, - const sp& captureListener) { + status_t captureDisplay(uint64_t displayOrLayerStack, + const sp& captureListener) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); SAFE_PARCEL(data.writeUint64, displayOrLayerStack); @@ -135,8 +137,8 @@ public: return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID, data, &reply); } - virtual status_t captureLayers(const LayerCaptureArgs& args, - const sp& captureListener) { + status_t captureLayers(const LayerCaptureArgs& args, + const sp& captureListener) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); SAFE_PARCEL(args.write, data); @@ -145,9 +147,8 @@ public: return remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply); } - virtual bool authenticateSurfaceTexture( - const sp& bufferProducer) const - { + bool authenticateSurfaceTexture( + const sp& bufferProducer) const override { Parcel data, reply; int err = NO_ERROR; err = data.writeInterfaceToken( @@ -180,8 +181,7 @@ public: return result != 0; } - virtual status_t getSupportedFrameTimestamps( - std::vector* outSupported) const { + status_t getSupportedFrameTimestamps(std::vector* outSupported) const override { if (!outSupported) { return UNEXPECTED_NULL; } @@ -224,8 +224,8 @@ public: return NO_ERROR; } - virtual sp createDisplayEventConnection( - VsyncSource vsyncSource, EventRegistrationFlags eventRegistration) { + sp createDisplayEventConnection( + VsyncSource vsyncSource, EventRegistrationFlags eventRegistration) override { Parcel data, reply; sp result; int err = data.writeInterfaceToken( @@ -247,8 +247,7 @@ public: return result; } - virtual sp createDisplay(const String8& displayName, bool secure) - { + sp createDisplay(const String8& displayName, bool secure) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); status_t status = data.writeString8(displayName); @@ -272,15 +271,14 @@ public: return display; } - virtual void destroyDisplay(const sp& display) - { + void destroyDisplay(const sp& display) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); remote()->transact(BnSurfaceComposer::DESTROY_DISPLAY, data, &reply); } - virtual std::vector getPhysicalDisplayIds() const { + std::vector getPhysicalDisplayIds() const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS, data, &reply) == @@ -297,7 +295,7 @@ public: return {}; } - virtual sp getPhysicalDisplayToken(PhysicalDisplayId displayId) const { + sp getPhysicalDisplayToken(PhysicalDisplayId displayId) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeUint64(displayId.value); @@ -305,8 +303,7 @@ public: return reply.readStrongBinder(); } - virtual void setPowerMode(const sp& display, int mode) - { + void setPowerMode(const sp& display, int mode) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -314,7 +311,7 @@ public: remote()->transact(BnSurfaceComposer::SET_POWER_MODE, data, &reply); } - virtual status_t getDisplayState(const sp& display, ui::DisplayState* state) { + status_t getDisplayState(const sp& display, ui::DisplayState* state) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -326,7 +323,7 @@ public: return result; } - virtual status_t getDisplayInfo(const sp& display, DisplayInfo* info) { + status_t getDisplayInfo(const sp& display, DisplayInfo* info) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -336,7 +333,8 @@ public: return reply.read(*info); } - virtual status_t getDisplayConfigs(const sp& display, Vector* configs) { + status_t getDisplayConfigs(const sp& display, + Vector* configs) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -354,9 +352,7 @@ public: return result; } - virtual status_t getDisplayStats(const sp& display, - DisplayStatInfo* stats) - { + status_t getDisplayStats(const sp& display, DisplayStatInfo* stats) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -370,8 +366,7 @@ public: return result; } - virtual int getActiveConfig(const sp& display) - { + int getActiveConfig(const sp& display) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -379,8 +374,8 @@ public: return reply.readInt32(); } - virtual status_t getDisplayColorModes(const sp& display, - Vector* outColorModes) { + status_t getDisplayColorModes(const sp& display, + Vector* outColorModes) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -409,8 +404,8 @@ public: return result; } - virtual status_t getDisplayNativePrimaries(const sp& display, - ui::DisplayPrimaries& primaries) { + status_t getDisplayNativePrimaries(const sp& display, + ui::DisplayPrimaries& primaries) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -435,7 +430,7 @@ public: return result; } - virtual ColorMode getActiveColorMode(const sp& display) { + ColorMode getActiveColorMode(const sp& display) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -455,8 +450,7 @@ public: return static_cast(reply.readInt32()); } - virtual status_t setActiveColorMode(const sp& display, - ColorMode colorMode) { + status_t setActiveColorMode(const sp& display, ColorMode colorMode) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -481,8 +475,8 @@ public: return static_cast(reply.readInt32()); } - virtual status_t getAutoLowLatencyModeSupport(const sp& display, - bool* outSupport) const { + status_t getAutoLowLatencyModeSupport(const sp& display, + bool* outSupport) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); status_t result = data.writeStrongBinder(display); @@ -499,7 +493,7 @@ public: return reply.readBool(outSupport); } - virtual void setAutoLowLatencyMode(const sp& display, bool on) { + void setAutoLowLatencyMode(const sp& display, bool on) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -524,7 +518,8 @@ public: } } - virtual status_t getGameContentTypeSupport(const sp& display, bool* outSupport) const { + status_t getGameContentTypeSupport(const sp& display, + bool* outSupport) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); status_t result = data.writeStrongBinder(display); @@ -540,7 +535,7 @@ public: return reply.readBool(outSupport); } - virtual void setGameContentType(const sp& display, bool on) { + void setGameContentType(const sp& display, bool on) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -563,7 +558,7 @@ public: } } - virtual status_t clearAnimationFrameStats() { + status_t clearAnimationFrameStats() override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -578,7 +573,7 @@ public: return reply.readInt32(); } - virtual status_t getAnimationFrameStats(FrameStats* outStats) const { + status_t getAnimationFrameStats(FrameStats* outStats) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::GET_ANIMATION_FRAME_STATS, data, &reply); @@ -586,8 +581,8 @@ public: return reply.readInt32(); } - virtual status_t getHdrCapabilities(const sp& display, - HdrCapabilities* outCapabilities) const { + status_t getHdrCapabilities(const sp& display, + HdrCapabilities* outCapabilities) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); status_t result = data.writeStrongBinder(display); @@ -608,7 +603,7 @@ public: return result; } - virtual status_t enableVSyncInjections(bool enable) { + status_t enableVSyncInjections(bool enable) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -629,7 +624,7 @@ public: return result; } - virtual status_t injectVSync(nsecs_t when) { + status_t injectVSync(nsecs_t when) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -650,7 +645,7 @@ public: return result; } - virtual status_t getLayerDebugInfo(std::vector* outLayers) { + status_t getLayerDebugInfo(std::vector* outLayers) override { if (!outLayers) { return UNEXPECTED_NULL; } @@ -680,10 +675,10 @@ public: return reply.readParcelableVector(outLayers); } - virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace, - ui::PixelFormat* defaultPixelFormat, - ui::Dataspace* wideColorGamutDataspace, - ui::PixelFormat* wideColorGamutPixelFormat) const { + status_t getCompositionPreference(ui::Dataspace* defaultDataspace, + ui::PixelFormat* defaultPixelFormat, + ui::Dataspace* wideColorGamutDataspace, + ui::PixelFormat* wideColorGamutPixelFormat) const override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -703,7 +698,7 @@ public: return error; } - virtual status_t getColorManagement(bool* outGetColorManagement) const { + status_t getColorManagement(bool* outGetColorManagement) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::GET_COLOR_MANAGEMENT, data, &reply); @@ -715,10 +710,10 @@ public: return err; } - virtual status_t getDisplayedContentSamplingAttributes(const sp& display, - ui::PixelFormat* outFormat, - ui::Dataspace* outDataspace, - uint8_t* outComponentMask) const { + status_t getDisplayedContentSamplingAttributes(const sp& display, + ui::PixelFormat* outFormat, + ui::Dataspace* outDataspace, + uint8_t* outComponentMask) const override { if (!outFormat || !outDataspace || !outComponentMask) return BAD_VALUE; Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -752,8 +747,8 @@ public: return error; } - virtual status_t setDisplayContentSamplingEnabled(const sp& display, bool enable, - uint8_t componentMask, uint64_t maxFrames) { + status_t setDisplayContentSamplingEnabled(const sp& display, bool enable, + uint8_t componentMask, uint64_t maxFrames) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -766,9 +761,9 @@ public: return result; } - virtual status_t getDisplayedContentSample(const sp& display, uint64_t maxFrames, - uint64_t timestamp, - DisplayedFrameStats* outStats) const { + status_t getDisplayedContentSample(const sp& display, uint64_t maxFrames, + uint64_t timestamp, + DisplayedFrameStats* outStats) const override { if (!outStats) return BAD_VALUE; Parcel data, reply; @@ -805,7 +800,7 @@ public: return result; } - virtual status_t getProtectedContentSupport(bool* outSupported) const { + status_t getProtectedContentSupport(bool* outSupported) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); status_t error = @@ -817,8 +812,8 @@ public: return error; } - virtual status_t isWideColorDisplay(const sp& token, - bool* outIsWideColorDisplay) const { + status_t isWideColorDisplay(const sp& token, + bool* outIsWideColorDisplay) const override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -837,9 +832,8 @@ public: return error; } - virtual status_t addRegionSamplingListener(const Rect& samplingArea, - const sp& stopLayerHandle, - const sp& listener) { + status_t addRegionSamplingListener(const Rect& samplingArea, const sp& stopLayerHandle, + const sp& listener) override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -868,7 +862,7 @@ public: return error; } - virtual status_t removeRegionSamplingListener(const sp& listener) { + status_t removeRegionSamplingListener(const sp& listener) override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -888,12 +882,11 @@ public: return error; } - virtual status_t setDesiredDisplayConfigSpecs(const sp& displayToken, - int32_t defaultConfig, bool allowGroupSwitching, - float primaryRefreshRateMin, - float primaryRefreshRateMax, - float appRequestRefreshRateMin, - float appRequestRefreshRateMax) { + status_t setDesiredDisplayConfigSpecs(const sp& displayToken, int32_t defaultConfig, + bool allowGroupSwitching, float primaryRefreshRateMin, + float primaryRefreshRateMax, + float appRequestRefreshRateMin, + float appRequestRefreshRateMax) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -947,13 +940,12 @@ public: return reply.readInt32(); } - virtual status_t getDesiredDisplayConfigSpecs(const sp& displayToken, - int32_t* outDefaultConfig, - bool* outAllowGroupSwitching, - float* outPrimaryRefreshRateMin, - float* outPrimaryRefreshRateMax, - float* outAppRequestRefreshRateMin, - float* outAppRequestRefreshRateMax) { + status_t getDesiredDisplayConfigSpecs(const sp& displayToken, + int32_t* outDefaultConfig, bool* outAllowGroupSwitching, + float* outPrimaryRefreshRateMin, + float* outPrimaryRefreshRateMax, + float* outAppRequestRefreshRateMin, + float* outAppRequestRefreshRateMax) override { if (!outDefaultConfig || !outAllowGroupSwitching || !outPrimaryRefreshRateMin || !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) { @@ -1011,8 +1003,8 @@ public: return reply.readInt32(); } - virtual status_t getDisplayBrightnessSupport(const sp& displayToken, - bool* outSupport) const { + status_t getDisplayBrightnessSupport(const sp& displayToken, + bool* outSupport) const override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -1039,7 +1031,7 @@ public: return NO_ERROR; } - virtual status_t setDisplayBrightness(const sp& displayToken, float brightness) { + status_t setDisplayBrightness(const sp& displayToken, float brightness) override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -1064,7 +1056,7 @@ public: return NO_ERROR; } - virtual status_t notifyPowerBoost(int32_t boostId) { + status_t notifyPowerBoost(int32_t boostId) override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -1085,8 +1077,8 @@ public: return NO_ERROR; } - virtual status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, - float lightPosY, float lightPosZ, float lightRadius) { + status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, + float lightPosY, float lightPosZ, float lightRadius) override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -1114,8 +1106,8 @@ public: return NO_ERROR; } - virtual status_t setFrameRate(const sp& surface, float frameRate, - int8_t compatibility, bool shouldBeSeamless) { + status_t setFrameRate(const sp& surface, float frameRate, + int8_t compatibility, bool shouldBeSeamless) override { Parcel data, reply; status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (err != NO_ERROR) { @@ -1156,7 +1148,7 @@ public: return reply.readInt32(); } - virtual status_t acquireFrameRateFlexibilityToken(sp* outToken) { + status_t acquireFrameRateFlexibilityToken(sp* outToken) override { if (!outToken) return BAD_VALUE; Parcel data, reply; @@ -1191,40 +1183,34 @@ public: return NO_ERROR; } - virtual status_t setFrameTimelineVsync(const sp& surface, - int64_t frameTimelineVsyncId) { + status_t setFrameTimelineInfo(const sp& surface, + const FrameTimelineInfo& frameTimelineInfo) override { Parcel data, reply; status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (err != NO_ERROR) { - ALOGE("setFrameTimelineVsync: failed writing interface token: %s (%d)", strerror(-err), - -err); + ALOGE("%s: failed writing interface token: %s (%d)", __func__, strerror(-err), -err); return err; } err = data.writeStrongBinder(IInterface::asBinder(surface)); if (err != NO_ERROR) { - ALOGE("setFrameTimelineVsync: failed writing strong binder: %s (%d)", strerror(-err), - -err); + ALOGE("%s: failed writing strong binder: %s (%d)", __func__, strerror(-err), -err); return err; } - err = data.writeInt64(frameTimelineVsyncId); - if (err != NO_ERROR) { - ALOGE("setFrameTimelineVsync: failed writing int64_t: %s (%d)", strerror(-err), -err); - return err; - } + SAFE_PARCEL(frameTimelineInfo.write, data); - err = remote()->transact(BnSurfaceComposer::SET_FRAME_TIMELINE_VSYNC, data, &reply); + err = remote()->transact(BnSurfaceComposer::SET_FRAME_TIMELINE_INFO, data, &reply); if (err != NO_ERROR) { - ALOGE("setFrameTimelineVsync: failed to transact: %s (%d)", strerror(-err), err); + ALOGE("%s: failed to transact: %s (%d)", __func__, strerror(-err), err); return err; } return reply.readInt32(); } - virtual status_t addTransactionTraceListener( - const sp& listener) { + status_t addTransactionTraceListener( + const sp& listener) override { Parcel data, reply; SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener)); @@ -1235,7 +1221,7 @@ public: /** * Get priority of the RenderEngine in surface flinger. */ - virtual int getGPUContextPriority() { + int getGPUContextPriority() override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); status_t err = @@ -1269,8 +1255,9 @@ status_t BnSurfaceComposer::onTransact( case SET_TRANSACTION_STATE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - int64_t frameTimelineVsyncId; - SAFE_PARCEL(data.readInt64, &frameTimelineVsyncId); + FrameTimelineInfo frameTimelineInfo; + SAFE_PARCEL(frameTimelineInfo.read, data); + uint32_t count = 0; SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize()); Vector state; @@ -1324,10 +1311,10 @@ status_t BnSurfaceComposer::onTransact( uint64_t transactionId = -1; SAFE_PARCEL(data.readUint64, &transactionId); - return setTransactionState(frameTimelineVsyncId, state, displays, stateFlags, - applyToken, inputWindowCommands, desiredPresentTime, - isAutoTimestamp, uncachedBuffer, hasListenerCallbacks, - listenerCallbacks, transactionId); + return setTransactionState(frameTimelineInfo, state, displays, stateFlags, applyToken, + inputWindowCommands, desiredPresentTime, isAutoTimestamp, + uncachedBuffer, hasListenerCallbacks, listenerCallbacks, + transactionId); } case BOOT_FINISHED: { CHECK_INTERFACE(ISurfaceComposer, data, reply); @@ -2078,30 +2065,26 @@ status_t BnSurfaceComposer::onTransact( } return NO_ERROR; } - case SET_FRAME_TIMELINE_VSYNC: { + case SET_FRAME_TIMELINE_INFO: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp binder; status_t err = data.readStrongBinder(&binder); if (err != NO_ERROR) { - ALOGE("setFrameTimelineVsync: failed to read strong binder: %s (%d)", - strerror(-err), -err); + ALOGE("setFrameTimelineInfo: failed to read strong binder: %s (%d)", strerror(-err), + -err); return err; } sp surface = interface_cast(binder); if (!surface) { - ALOGE("setFrameTimelineVsync: failed to cast to IGraphicBufferProducer: %s (%d)", + ALOGE("setFrameTimelineInfo: failed to cast to IGraphicBufferProducer: %s (%d)", strerror(-err), -err); return err; } - int64_t frameTimelineVsyncId; - err = data.readInt64(&frameTimelineVsyncId); - if (err != NO_ERROR) { - ALOGE("setFrameTimelineVsync: failed to read int64_t: %s (%d)", strerror(-err), - -err); - return err; - } - status_t result = setFrameTimelineVsync(surface, frameTimelineVsyncId); + FrameTimelineInfo frameTimelineInfo; + SAFE_PARCEL(frameTimelineInfo.read, data); + + status_t result = setFrameTimelineInfo(surface, frameTimelineInfo); reply->writeInt32(result); return NO_ERROR; } diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp index 180857185c..0ded9361bf 100644 --- a/libs/gui/ITransactionCompletedListener.cpp +++ b/libs/gui/ITransactionCompletedListener.cpp @@ -92,10 +92,8 @@ status_t FrameEventHistoryStats::readFromParcel(const Parcel* input) { return err; } -JankData::JankData() : - frameVsyncId(ISurfaceComposer::INVALID_VSYNC_ID), - jankType(JankType::None) { -} +JankData::JankData() + : frameVsyncId(FrameTimelineInfo::INVALID_VSYNC_ID), jankType(JankType::None) {} status_t JankData::writeToParcel(Parcel* output) const { SAFE_PARCEL(output->writeInt64, frameVsyncId); diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index e5e10a0014..2aac87c9d0 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -63,7 +63,7 @@ layer_state_t::layer_state_t() shouldBeSeamless(true), fixedTransformHint(ui::Transform::ROT_INVALID), frameNumber(0), - frameTimelineVsyncId(ISurfaceComposer::INVALID_VSYNC_ID), + frameTimelineInfo(), autoRefresh(false) { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; @@ -151,7 +151,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeBool, shouldBeSeamless); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeUint64, frameNumber); - SAFE_PARCEL(output.writeInt64, frameTimelineVsyncId); + SAFE_PARCEL(frameTimelineInfo.write, output); SAFE_PARCEL(output.writeBool, autoRefresh); SAFE_PARCEL(output.writeUint32, blurRegions.size()); @@ -272,7 +272,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast(tmpUint32); SAFE_PARCEL(input.readUint64, &frameNumber); - SAFE_PARCEL(input.readInt64, &frameTimelineVsyncId); + SAFE_PARCEL(frameTimelineInfo.read, input); SAFE_PARCEL(input.readBool, &autoRefresh); uint32_t numRegions = 0; @@ -539,15 +539,9 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eFrameNumberChanged; frameNumber = other.frameNumber; } - if (other.what & eFrameTimelineVsyncChanged) { - // When merging vsync Ids we take the oldest valid one - if (frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID && - other.frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID) { - frameTimelineVsyncId = std::max(frameTimelineVsyncId, other.frameTimelineVsyncId); - } else if (frameTimelineVsyncId == ISurfaceComposer::INVALID_VSYNC_ID) { - frameTimelineVsyncId = other.frameTimelineVsyncId; - } - what |= eFrameTimelineVsyncChanged; + if (other.what & eFrameTimelineInfoChanged) { + what |= eFrameTimelineInfoChanged; + frameTimelineInfo.merge(other.frameTimelineInfo); } if (other.what & eAutoRefreshChanged) { what |= eAutoRefreshChanged; diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e82f0cc9e9..59ad8d28bd 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1496,8 +1496,8 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER: res = dispatchGetLastQueuedBuffer(args); break; - case NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC: - res = dispatchSetFrameTimelineVsync(args); + case NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO: + res = dispatchSetFrameTimelineInfo(args); break; default: res = NAME_NOT_FOUND; @@ -1806,12 +1806,13 @@ int Surface::dispatchGetLastQueuedBuffer(va_list args) { return result; } -int Surface::dispatchSetFrameTimelineVsync(va_list args) { +int Surface::dispatchSetFrameTimelineInfo(va_list args) { ATRACE_CALL(); auto frameTimelineVsyncId = static_cast(va_arg(args, int64_t)); + auto inputEventId = static_cast(va_arg(args, int32_t)); - ALOGV("Surface::dispatchSetFrameTimelineVsync"); - return setFrameTimelineVsync(frameTimelineVsyncId); + ALOGV("Surface::%s", __func__); + return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId}); } bool Surface::transformToDisplayInverse() { @@ -2579,9 +2580,8 @@ status_t Surface::setFrameRate(float frameRate, int8_t compatibility, bool shoul shouldBeSeamless); } -status_t Surface::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { - return composerService()->setFrameTimelineVsync(mGraphicBufferProducer, - frameTimelineVsyncId); +status_t Surface::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) { + return composerService()->setFrameTimelineInfo(mGraphicBufferProducer, frameTimelineInfo); } }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 78f655a71b..7de256d09c 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -396,7 +396,7 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other) mContainsBuffer(other.mContainsBuffer), mDesiredPresentTime(other.mDesiredPresentTime), mIsAutoTimestamp(other.mIsAutoTimestamp), - mFrameTimelineVsyncId(other.mFrameTimelineVsyncId), + mFrameTimelineInfo(other.mFrameTimelineInfo), mApplyToken(other.mApplyToken) { mDisplayStates = other.mDisplayStates; mComposerStates = other.mComposerStates; @@ -427,7 +427,9 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel const bool containsBuffer = parcel->readBool(); const int64_t desiredPresentTime = parcel->readInt64(); const bool isAutoTimestamp = parcel->readBool(); - const int64_t frameTimelineVsyncId = parcel->readInt64(); + FrameTimelineInfo frameTimelineInfo; + SAFE_PARCEL(frameTimelineInfo.read, *parcel); + sp applyToken; parcel->readNullableStrongBinder(&applyToken); size_t count = static_cast(parcel->readUint32()); @@ -502,7 +504,7 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel mContainsBuffer = containsBuffer; mDesiredPresentTime = desiredPresentTime; mIsAutoTimestamp = isAutoTimestamp; - mFrameTimelineVsyncId = frameTimelineVsyncId; + mFrameTimelineInfo = frameTimelineInfo; mDisplayStates = displayStates; mListenerCallbacks = listenerCallbacks; mComposerStates = composerStates; @@ -534,7 +536,7 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const parcel->writeBool(mContainsBuffer); parcel->writeInt64(mDesiredPresentTime); parcel->writeBool(mIsAutoTimestamp); - parcel->writeInt64(mFrameTimelineVsyncId); + SAFE_PARCEL(mFrameTimelineInfo.write, *parcel); parcel->writeStrongBinder(mApplyToken); parcel->writeUint32(static_cast(mDisplayStates.size())); for (auto const& displayState : mDisplayStates) { @@ -613,13 +615,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mExplicitEarlyWakeupEnd = mExplicitEarlyWakeupEnd || other.mExplicitEarlyWakeupEnd; mApplyToken = other.mApplyToken; - // When merging vsync Ids we take the oldest one - if (mFrameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID && - other.mFrameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID) { - mFrameTimelineVsyncId = std::max(mFrameTimelineVsyncId, other.mFrameTimelineVsyncId); - } else if (mFrameTimelineVsyncId == ISurfaceComposer::INVALID_VSYNC_ID) { - mFrameTimelineVsyncId = other.mFrameTimelineVsyncId; - } + mFrameTimelineInfo.merge(other.mFrameTimelineInfo); other.clear(); return *this; @@ -639,7 +635,7 @@ void SurfaceComposerClient::Transaction::clear() { mExplicitEarlyWakeupEnd = false; mDesiredPresentTime = 0; mIsAutoTimestamp = true; - mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; + mFrameTimelineInfo.clear(); mApplyToken = nullptr; } @@ -651,9 +647,8 @@ void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { uncacheBuffer.id = cacheId; sp applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); - sf->setTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, {}, {}, 0, applyToken, {}, - systemTime(), true, uncacheBuffer, false, {}, - 0 /* Undefined transactionId */); + sf->setTransactionState(FrameTimelineInfo{}, {}, {}, 0, applyToken, {}, systemTime(), true, + uncacheBuffer, false, {}, 0 /* Undefined transactionId */); } void SurfaceComposerClient::Transaction::cacheBuffers() { @@ -773,7 +768,7 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { ? mApplyToken : IInterface::asBinder(TransactionCompletedListener::getIInstance()); - sf->setTransactionState(mFrameTimelineVsyncId, composerStates, displayStates, flags, applyToken, + sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken, mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp, {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/, hasListenerCallbacks, listenerCallbacks, mId); @@ -1548,22 +1543,22 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixed return *this; } -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineVsync( - int64_t frameTimelineVsyncId) { - mFrameTimelineVsyncId = frameTimelineVsyncId; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo( + const FrameTimelineInfo& frameTimelineInfo) { + mFrameTimelineInfo = frameTimelineInfo; return *this; } -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineVsync( - const sp& sc, int64_t frameTimelineVsyncId) { +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo( + const sp& sc, const FrameTimelineInfo& frameTimelineInfo) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } - s->what |= layer_state_t::eFrameTimelineVsyncChanged; - s->frameTimelineVsyncId = frameTimelineVsyncId; + s->what |= layer_state_t::eFrameTimelineInfoChanged; + s->frameTimelineInfo = frameTimelineInfo; return *this; } diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 411526eeb3..59c400a79e 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -92,7 +92,7 @@ public: void flushShadowQueue() { mFlushShadowQueue = true; } status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); - status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId); + status_t setFrameTimelineInfo(const FrameTimelineInfo& info); virtual ~BLASTBufferQueue(); @@ -156,7 +156,7 @@ private: // This is only relevant for shared buffer mode. bool mAutoRefresh GUARDED_BY(mMutex) = false; - std::queue mNextFrameTimelineVsyncIdQueue GUARDED_BY(mMutex); + std::queue mNextFrameTimelineInfoQueue GUARDED_BY(mMutex); // Last acquired buffer's scaling mode. This is used to check if we should update the blast // layer size immediately or wait until we get the next buffer. This will support scenarios diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h index 5587acf08f..f446dd88ed 100644 --- a/libs/gui/include/gui/DisplayEventDispatcher.h +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -25,7 +25,7 @@ struct VsyncEventData { // The Vsync Id corresponsing to this vsync event. This will be used to // populate ISurfaceComposer::setFrameTimelineVsync and // SurfaceComposerClient::setFrameTimelineVsync - int64_t id = ISurfaceComposer::INVALID_VSYNC_ID; + int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID; // The deadline in CLOCK_MONOTONIC that the app needs to complete its // frame by (both on the CPU and the GPU) diff --git a/libs/gui/include/gui/FrameTimelineInfo.h b/libs/gui/include/gui/FrameTimelineInfo.h new file mode 100644 index 0000000000..3b4c009609 --- /dev/null +++ b/libs/gui/include/gui/FrameTimelineInfo.h @@ -0,0 +1,43 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include + +namespace android { + +struct FrameTimelineInfo { + // Needs to be in sync with android.graphics.FrameInfo.INVALID_VSYNC_ID in java + static constexpr int64_t INVALID_VSYNC_ID = -1; + + // The vsync id that was used to start the transaction + int64_t vsyncId = INVALID_VSYNC_ID; + + // The id of the input event that caused this buffer + int32_t inputEventId = android::os::IInputConstants::INVALID_INPUT_EVENT_ID; + + status_t write(Parcel& output) const; + status_t read(const Parcel& input); + + void merge(const FrameTimelineInfo& other); + void clear(); +}; + +} // namespace android diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 86f3c605ab..81ff6b0d8d 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -117,9 +118,6 @@ public: using EventRegistrationFlags = Flags; - // Needs to be in sync with android.graphics.FrameInfo.INVALID_VSYNC_ID in java - static constexpr int64_t INVALID_VSYNC_ID = -1; - /* * Create a connection with SurfaceFlinger. */ @@ -164,7 +162,7 @@ public: /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */ virtual status_t setTransactionState( - int64_t frameTimelineVsyncId, const Vector& state, + const FrameTimelineInfo& frameTimelineInfo, const Vector& state, const Vector& displays, uint32_t flags, const sp& applyToken, const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, @@ -494,11 +492,11 @@ public: virtual status_t acquireFrameRateFlexibilityToken(sp* outToken) = 0; /* - * Sets the frame timeline vsync id received from choreographer that corresponds to next + * Sets the frame timeline vsync info received from choreographer that corresponds to next * buffer submitted on that surface. */ - virtual status_t setFrameTimelineVsync(const sp& surface, - int64_t frameTimelineVsyncId) = 0; + virtual status_t setFrameTimelineInfo(const sp& surface, + const FrameTimelineInfo& frameTimelineInfo) = 0; /* * Adds a TransactionTraceListener to listen for transaction tracing state updates. @@ -569,7 +567,7 @@ public: SET_GAME_CONTENT_TYPE, SET_FRAME_RATE, ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN, - SET_FRAME_TIMELINE_VSYNC, + SET_FRAME_TIMELINE_INFO, ADD_TRANSACTION_TRACE_LISTENER, GET_GPU_CONTEXT_PRIORITY, // Always append new enum to the end. diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 83a9d3356e..800f86ee92 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -128,7 +128,7 @@ struct layer_state_t { eProducerDisconnect = 0x100'00000000, eFixedTransformHintChanged = 0x200'00000000, eFrameNumberChanged = 0x400'00000000, - eFrameTimelineVsyncChanged = 0x800'00000000, + eFrameTimelineInfoChanged = 0x800'00000000, eBlurRegionsChanged = 0x1000'00000000, eAutoRefreshChanged = 0x2000'00000000, }; @@ -234,7 +234,7 @@ struct layer_state_t { // graphics producer. uint64_t frameNumber; - int64_t frameTimelineVsyncId; + FrameTimelineInfo frameTimelineInfo; // Indicates that the consumer should acquire the next frame as soon as it // can and not wait for a frame to become available. This is only relevant diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 43b5dcd60d..b6b5c7ca5e 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -18,6 +18,7 @@ #define ANDROID_GUI_SURFACE_H #include +#include #include #include #include @@ -187,7 +188,7 @@ public: status_t getConsumerUsage(uint64_t* outUsage) const; virtual status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); - virtual status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId); + virtual status_t setFrameTimelineInfo(const FrameTimelineInfo& info); protected: virtual ~Surface(); @@ -273,7 +274,7 @@ private: int dispatchAddQueueInterceptor(va_list args); int dispatchAddQueryInterceptor(va_list args); int dispatchGetLastQueuedBuffer(va_list args); - int dispatchSetFrameTimelineVsync(va_list args); + int dispatchSetFrameTimelineInfo(va_list args); bool transformToDisplayInverse(); protected: diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 11db658de2..bed5c44110 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -385,8 +385,8 @@ public: int64_t mDesiredPresentTime = 0; bool mIsAutoTimestamp = true; - // The vsync Id provided by Choreographer.getVsyncId - int64_t mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; + // The vsync id provided by Choreographer.getVsyncId and the input event id + FrameTimelineInfo mFrameTimelineInfo; // If not null, transactions will be queued up using this token otherwise a common token // per process will be used. @@ -546,11 +546,12 @@ public: Transaction& setFixedTransformHint(const sp& sc, int32_t transformHint); // Sets the frame timeline vsync id received from choreographer that corresponds - // to the transaction. - Transaction& setFrameTimelineVsync(int64_t frameTimelineVsyncId); + // to the transaction, and the input event id that identifies the input event that caused + // the current frame. + Transaction& setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo); // Variant that only applies to a specific SurfaceControl. - Transaction& setFrameTimelineVsync(const sp& sc, - int64_t frameTimelineVsyncId); + Transaction& setFrameTimelineInfo(const sp& sc, + const FrameTimelineInfo& frameTimelineInfo); // Indicates that the consumer should acquire the next frame as soon as it // can and not wait for a frame to become available. This is only relevant diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 63db9a7b96..3f7a5b1785 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -695,7 +695,7 @@ public: void destroyDisplay(const sp& /*display */) override {} std::vector getPhysicalDisplayIds() const override { return {}; } sp getPhysicalDisplayToken(PhysicalDisplayId) const override { return nullptr; } - status_t setTransactionState(int64_t /*frameTimelineVsyncId*/, + status_t setTransactionState(const FrameTimelineInfo& /*frameTimelineInfo*/, const Vector& /*state*/, const Vector& /*displays*/, uint32_t /*flags*/, const sp& /*applyToken*/, @@ -877,8 +877,8 @@ public: return NO_ERROR; } - status_t setFrameTimelineVsync(const sp& /*surface*/, - int64_t /*frameTimelineVsyncId*/) override { + status_t setFrameTimelineInfo(const sp& /*surface*/, + const FrameTimelineInfo& /*frameTimelineInfo*/) override { return NO_ERROR; } diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl index c69a53a784..bce0ec8367 100644 --- a/libs/input/android/os/IInputConstants.aidl +++ b/libs/input/android/os/IInputConstants.aidl @@ -31,4 +31,10 @@ interface IInputConstants // Indicate invalid battery capacity const int INVALID_BATTERY_CAPACITY = -1; + + /** + * Every input event has an id. This constant value is used when a valid input event id is not + * available. + */ + const int INVALID_INPUT_EVENT_ID = 0; } diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 82d2e661b4..ffe4412b72 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -255,7 +255,7 @@ enum { NATIVE_WINDOW_ALLOCATE_BUFFERS = 45, /* private */ NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER = 46, /* private */ NATIVE_WINDOW_SET_QUERY_INTERCEPTOR = 47, /* private */ - NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC = 48, /* private */ + NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO = 48, /* private */ // clang-format on }; @@ -1023,10 +1023,11 @@ static inline int native_window_set_frame_rate(struct ANativeWindow* window, flo (int)compatibility, (int)shouldBeSeamless); } -static inline int native_window_set_frame_timeline_vsync(struct ANativeWindow* window, - int64_t frameTimelineVsyncId) { - return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC, - frameTimelineVsyncId); +static inline int native_window_set_frame_timeline_info(struct ANativeWindow* window, + int64_t frameTimelineVsyncId, + int32_t inputEventId) { + return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO, + frameTimelineVsyncId, inputEventId); } // ------------------------------------------------------------------------------------------------ diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 32e6b1098f..52197873c5 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -384,8 +384,8 @@ status_t BufferQueueLayer::updateFrameNumber(nsecs_t latchTime) { return NO_ERROR; } -void BufferQueueLayer::setFrameTimelineVsyncForBuffer(int64_t frameTimelineVsyncId) { - mFrameTimelineVsyncId = frameTimelineVsyncId; +void BufferQueueLayer::setFrameTimelineInfoForBuffer(const FrameTimelineInfo& frameTimelineInfo) { + mFrameTimelineInfo = frameTimelineInfo; } // ----------------------------------------------------------------------- @@ -445,9 +445,8 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { } auto surfaceFrame = - mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineVsyncId, - mOwnerPid, mOwnerUid, mName, - mName); + mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineInfo, mOwnerPid, + mOwnerUid, mName, mName); surfaceFrame->setActualQueueTime(systemTime()); mQueueItems.push_back({item, surfaceFrame}); @@ -485,9 +484,8 @@ void BufferQueueLayer::onFrameReplaced(const BufferItem& item) { } auto surfaceFrame = - mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineVsyncId, - mOwnerPid, mOwnerUid, mName, - mName); + mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineInfo, mOwnerPid, + mOwnerUid, mName, mName); surfaceFrame->setActualQueueTime(systemTime()); mQueueItems[mQueueItems.size() - 1].item = item; mQueueItems[mQueueItems.size() - 1].surfaceFrame = std::move(surfaceFrame); diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index 0e8fdbe092..41ff01262e 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -101,7 +101,7 @@ private: status_t updateActiveBuffer() override; status_t updateFrameNumber(nsecs_t latchTime) override; - void setFrameTimelineVsyncForBuffer(int64_t frameTimelineVsyncId) override; + void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& frameTimelineInfo) override; sp createClone() override; @@ -145,10 +145,10 @@ private: sp mContentsChangedListener; - // The last vsync id received on this layer. This will be used when we get + // The last vsync info received on this layer. This will be used when we get // a buffer to correlate the buffer with the vsync id. Can only be accessed // with the SF state lock held. - std::optional mFrameTimelineVsyncId; + FrameTimelineInfo mFrameTimelineInfo; // Keeps track of the time SF latched the last buffer from this layer. // Used in buffer stuffing analysis in FrameTimeline. diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 17d1f3bff7..3743716876 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -275,13 +275,15 @@ int64_t TraceCookieCounter::getCookieForTracing() { return ++mTraceCookie; } -SurfaceFrame::SurfaceFrame(int64_t token, pid_t ownerPid, uid_t ownerUid, std::string layerName, - std::string debugName, PredictionState predictionState, +SurfaceFrame::SurfaceFrame(const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, + uid_t ownerUid, std::string layerName, std::string debugName, + PredictionState predictionState, frametimeline::TimelineItem&& predictions, std::shared_ptr timeStats, JankClassificationThresholds thresholds, TraceCookieCounter* traceCookieCounter) - : mToken(token), + : mToken(frameTimelineInfo.vsyncId), + mInputEventId(frameTimelineInfo.inputEventId), mOwnerPid(ownerPid), mOwnerUid(ownerUid), mLayerName(std::move(layerName)), @@ -295,27 +297,27 @@ SurfaceFrame::SurfaceFrame(int64_t token, pid_t ownerPid, uid_t ownerUid, std::s mTraceCookieCounter(*traceCookieCounter) {} void SurfaceFrame::setActualStartTime(nsecs_t actualStartTime) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mActuals.startTime = actualStartTime; } void SurfaceFrame::setActualQueueTime(nsecs_t actualQueueTime) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mActualQueueTime = actualQueueTime; } void SurfaceFrame::setAcquireFenceTime(nsecs_t acquireFenceTime) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mActuals.endTime = std::max(acquireFenceTime, mActualQueueTime); } void SurfaceFrame::setPresentState(PresentState presentState, nsecs_t lastLatchTime) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mPresentState = presentState; mLastLatchTime = lastLatchTime; } std::optional SurfaceFrame::getJankType() const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); if (mActuals.presentTime == 0) { return std::nullopt; } @@ -323,32 +325,32 @@ std::optional SurfaceFrame::getJankType() const { } nsecs_t SurfaceFrame::getBaseTime() const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); return getMinTime(mPredictionState, mPredictions, mActuals); } TimelineItem SurfaceFrame::getActuals() const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); return mActuals; } SurfaceFrame::PresentState SurfaceFrame::getPresentState() const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); return mPresentState; } FramePresentMetadata SurfaceFrame::getFramePresentMetadata() const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); return mFramePresentMetadata; } FrameReadyMetadata SurfaceFrame::getFrameReadyMetadata() const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); return mFrameReadyMetadata; } void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t baseTime) const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); StringAppendF(&result, "%s", indent.c_str()); StringAppendF(&result, "Layer - %s", mDebugName.c_str()); if (mJankType != JankType::None) { @@ -387,7 +389,7 @@ void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, nsecs_t vsyncPeriod) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); if (mPresentState != PresentState::Presented) { // No need to update dropped buffers return; @@ -479,6 +481,9 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType); } +/** + * TODO(b/178637512): add inputEventId to the perfetto trace. + */ void SurfaceFrame::trace(int64_t displayFrameToken) { using FrameTimelineDataSource = impl::FrameTimeline::FrameTimelineDataSource; @@ -486,12 +491,12 @@ void SurfaceFrame::trace(int64_t displayFrameToken) { bool missingToken = false; // Expected timeline start FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { - std::lock_guard lock(mMutex); - if (mToken == ISurfaceComposer::INVALID_VSYNC_ID) { + std::scoped_lock lock(mMutex); + if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) { ALOGD("Cannot trace SurfaceFrame - %s with invalid token", mLayerName.c_str()); missingToken = true; return; - } else if (displayFrameToken == ISurfaceComposer::INVALID_VSYNC_ID) { + } else if (displayFrameToken == FrameTimelineInfo::INVALID_VSYNC_ID) { ALOGD("Cannot trace SurfaceFrame - %s with invalid displayFrameToken", mLayerName.c_str()); missingToken = true; @@ -521,7 +526,7 @@ void SurfaceFrame::trace(int64_t displayFrameToken) { // Expected timeline end FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); auto packet = ctx.NewTracePacket(); packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC); packet->set_timestamp(static_cast(mPredictions.endTime)); @@ -535,7 +540,7 @@ void SurfaceFrame::trace(int64_t displayFrameToken) { int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing(); // Actual timeline start FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); auto packet = ctx.NewTracePacket(); packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC); // Actual start time is not yet available, so use expected start instead @@ -566,7 +571,7 @@ void SurfaceFrame::trace(int64_t displayFrameToken) { }); // Actual timeline end FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); auto packet = ctx.NewTracePacket(); packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC); packet->set_timestamp(static_cast(mActuals.endTime)); @@ -582,7 +587,7 @@ namespace impl { int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) { ATRACE_CALL(); - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); const int64_t assignedToken = mCurrentToken++; mPredictions[assignedToken] = {systemTime(), predictions}; flushTokens(systemTime()); @@ -590,7 +595,7 @@ int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) { } std::optional TokenManager::getPredictionsForToken(int64_t token) const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); auto predictionsIterator = mPredictions.find(token); if (predictionsIterator != mPredictions.end()) { return predictionsIterator->second.predictions; @@ -634,26 +639,28 @@ void FrameTimeline::registerDataSource() { } std::shared_ptr FrameTimeline::createSurfaceFrameForToken( - std::optional token, pid_t ownerPid, uid_t ownerUid, std::string layerName, - std::string debugName) { + const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, + std::string layerName, std::string debugName) { ATRACE_CALL(); - if (!token) { - return std::make_shared(ISurfaceComposer::INVALID_VSYNC_ID, ownerPid, - ownerUid, std::move(layerName), std::move(debugName), + if (frameTimelineInfo.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) { + return std::make_shared(frameTimelineInfo, ownerPid, ownerUid, + std::move(layerName), std::move(debugName), PredictionState::None, TimelineItem(), mTimeStats, mJankClassificationThresholds, &mTraceCookieCounter); } - std::optional predictions = mTokenManager.getPredictionsForToken(*token); + std::optional predictions = + mTokenManager.getPredictionsForToken(frameTimelineInfo.vsyncId); if (predictions) { - return std::make_shared(*token, ownerPid, ownerUid, std::move(layerName), - std::move(debugName), PredictionState::Valid, - std::move(*predictions), mTimeStats, - mJankClassificationThresholds, &mTraceCookieCounter); - } - return std::make_shared(*token, ownerPid, ownerUid, std::move(layerName), - std::move(debugName), PredictionState::Expired, - TimelineItem(), mTimeStats, mJankClassificationThresholds, - &mTraceCookieCounter); + return std::make_shared(frameTimelineInfo, ownerPid, ownerUid, + std::move(layerName), std::move(debugName), + PredictionState::Valid, std::move(*predictions), + mTimeStats, mJankClassificationThresholds, + &mTraceCookieCounter); + } + return std::make_shared(frameTimelineInfo, ownerPid, ownerUid, + std::move(layerName), std::move(debugName), + PredictionState::Expired, TimelineItem(), mTimeStats, + mJankClassificationThresholds, &mTraceCookieCounter); } FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr timeStats, @@ -669,13 +676,13 @@ FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr timeStats, void FrameTimeline::addSurfaceFrame(std::shared_ptr surfaceFrame) { ATRACE_CALL(); - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mCurrentDisplayFrame->addSurfaceFrame(surfaceFrame); } void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, nsecs_t vsyncPeriod) { ATRACE_CALL(); - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mCurrentDisplayFrame->onSfWakeUp(token, vsyncPeriod, mTokenManager.getPredictionsForToken(token), wakeUpTime); } @@ -683,7 +690,7 @@ void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, nsecs_t vsync void FrameTimeline::setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr& presentFence) { ATRACE_CALL(); - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mCurrentDisplayFrame->setActualEndTime(sfPresentTime); mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame)); flushPendingPresentFences(); @@ -826,7 +833,7 @@ void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const { // Expected timeline start FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { auto packet = ctx.NewTracePacket(); - if (mToken == ISurfaceComposer::INVALID_VSYNC_ID) { + if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) { ALOGD("Cannot trace DisplayFrame with invalid token"); missingToken = true; return; @@ -999,7 +1006,7 @@ void FrameTimeline::DisplayFrame::dump(std::string& result, nsecs_t baseTime) co } void FrameTimeline::dumpAll(std::string& result) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); StringAppendF(&result, "Number of display frames : %d\n", (int)mDisplayFrames.size()); nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : mDisplayFrames[0]->getBaseTime(); for (size_t i = 0; i < mDisplayFrames.size(); i++) { @@ -1009,7 +1016,7 @@ void FrameTimeline::dumpAll(std::string& result) { } void FrameTimeline::dumpJank(std::string& result) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : mDisplayFrames[0]->getBaseTime(); for (size_t i = 0; i < mDisplayFrames.size(); i++) { mDisplayFrames[i]->dumpJank(result, baseTime, static_cast(i)); @@ -1031,7 +1038,7 @@ void FrameTimeline::parseArgs(const Vector& args, std::string& result) } void FrameTimeline::setMaxDisplayFrames(uint32_t size) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); // The size can either increase or decrease, clear everything, to be consistent mDisplayFrames.clear(); diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h index ed38cc6375..54e8efbc92 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h @@ -154,10 +154,10 @@ public: // Only FrameTimeline can construct a SurfaceFrame as it provides Predictions(through // TokenManager), Thresholds and TimeStats pointer. - SurfaceFrame(int64_t token, pid_t ownerPid, uid_t ownerUid, std::string layerName, - std::string debugName, PredictionState predictionState, TimelineItem&& predictions, - std::shared_ptr timeStats, JankClassificationThresholds thresholds, - TraceCookieCounter* traceCookieCounter); + SurfaceFrame(const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, + std::string layerName, std::string debugName, PredictionState predictionState, + TimelineItem&& predictions, std::shared_ptr timeStats, + JankClassificationThresholds thresholds, TraceCookieCounter* traceCookieCounter); ~SurfaceFrame() = default; // Returns std::nullopt if the frame hasn't been classified yet. @@ -166,6 +166,7 @@ public: // Functions called by SF int64_t getToken() const { return mToken; }; + int32_t getInputEventId() const { return mInputEventId; }; TimelineItem getPredictions() const { return mPredictions; }; // Actual timestamps of the app are set individually at different functions. // Start time (if the app provides) and Queue time are accessible after queueing the frame, @@ -198,6 +199,7 @@ public: private: const int64_t mToken; + const int32_t mInputEventId; const pid_t mOwnerPid; const uid_t mOwnerUid; const std::string mLayerName; @@ -243,10 +245,9 @@ public: // Create a new surface frame, set the predictions based on a token and return it to the caller. // Debug name is the human-readable debugging string for dumpsys. - virtual std::shared_ptr createSurfaceFrameForToken(std::optional token, - pid_t ownerPid, uid_t ownerUid, - std::string layerName, - std::string debugName) = 0; + virtual std::shared_ptr createSurfaceFrameForToken( + const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, + std::string layerName, std::string debugName) = 0; // Adds a new SurfaceFrame to the current DisplayFrame. Frames from multiple layers can be // composited into one display frame. @@ -279,7 +280,7 @@ namespace impl { class TokenManager : public android::frametimeline::TokenManager { public: - TokenManager() : mCurrentToken(ISurfaceComposer::INVALID_VSYNC_ID + 1) {} + TokenManager() : mCurrentToken(FrameTimelineInfo::INVALID_VSYNC_ID + 1) {} ~TokenManager() = default; int64_t generateTokenForPredictions(TimelineItem&& predictions) override; @@ -353,7 +354,7 @@ public: private: void dump(std::string& result, nsecs_t baseTime) const; - int64_t mToken = ISurfaceComposer::INVALID_VSYNC_ID; + int64_t mToken = FrameTimelineInfo::INVALID_VSYNC_ID; /* Usage of TimelineItem w.r.t SurfaceFlinger * startTime Time when SurfaceFlinger wakes up to handle transactions and buffer updates @@ -393,10 +394,9 @@ public: ~FrameTimeline() = default; frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; } - std::shared_ptr createSurfaceFrameForToken(std::optional token, - pid_t ownerPid, uid_t ownerUid, - std::string layerName, - std::string debugName) override; + std::shared_ptr createSurfaceFrameForToken( + const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, + std::string layerName, std::string debugName) override; void addSurfaceFrame(std::shared_ptr surfaceFrame) override; void setSfWakeUp(int64_t token, nsecs_t wakeupTime, nsecs_t vsyncPeriod) override; void setSfPresent(nsecs_t sfPresentTime, diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 66ce3f1a44..aeaa7e2d67 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -129,7 +129,7 @@ Layer::Layer(const LayerCreationArgs& args) mCurrentState.shadowRadius = 0.f; mCurrentState.treeHasFrameRateVote = false; mCurrentState.fixedTransformHint = ui::Transform::ROT_INVALID; - mCurrentState.frameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; + mCurrentState.frameTimelineInfo = {}; mCurrentState.postTime = -1; if (args.flags & ISurfaceComposerClient::eNoColorFill) { @@ -907,14 +907,10 @@ bool Layer::applyPendingStates(State* stateToCommit) { } if (stateUpdateAvailable) { - const auto vsyncId = - stateToCommit->frameTimelineVsyncId == ISurfaceComposer::INVALID_VSYNC_ID - ? std::nullopt - : std::make_optional(stateToCommit->frameTimelineVsyncId); - mSurfaceFrame = - mFlinger->mFrameTimeline->createSurfaceFrameForToken(vsyncId, mOwnerPid, mOwnerUid, - mName, mTransactionName); + mFlinger->mFrameTimeline + ->createSurfaceFrameForToken(stateToCommit->frameTimelineInfo, mOwnerPid, + mOwnerUid, mName, mTransactionName); mSurfaceFrame->setActualQueueTime(stateToCommit->postTime); // For transactions we set the acquire fence time to the post time as we // don't have a buffer. For BufferStateLayer it is overridden in @@ -1313,7 +1309,7 @@ bool Layer::setBlurRegions(const std::vector& blurRegions) { } bool Layer::setFlags(uint8_t flags, uint8_t mask) { - const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask); + const uint8_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask); if (mCurrentState.flags == newFlags) return false; mCurrentState.sequence++; mCurrentState.flags = newFlags; @@ -1491,8 +1487,8 @@ bool Layer::setFrameRate(FrameRate frameRate) { return true; } -void Layer::setFrameTimelineVsyncForTransaction(int64_t frameTimelineVsyncId, nsecs_t postTime) { - mCurrentState.frameTimelineVsyncId = frameTimelineVsyncId; +void Layer::setFrameTimelineInfoForTransaction(const FrameTimelineInfo& info, nsecs_t postTime) { + mCurrentState.frameTimelineInfo = info; mCurrentState.postTime = postTime; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 359340eb64..9b33beb620 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -304,8 +304,8 @@ public: // a fixed transform hint is not set. ui::Transform::RotationFlags fixedTransformHint; - // The vsync id that was used to start the transaction - int64_t frameTimelineVsyncId; + // The vsync info that was used to start the transaction + FrameTimelineInfo frameTimelineInfo; // When the transaction was posted nsecs_t postTime; @@ -869,8 +869,9 @@ public: bool setFrameRate(FrameRate); - virtual void setFrameTimelineVsyncForBuffer(int64_t /*frameTimelineVsyncId*/) {} - void setFrameTimelineVsyncForTransaction(int64_t frameTimelineVsyncId, nsecs_t postTime); + virtual void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {} + void setFrameTimelineInfoForTransaction(const FrameTimelineInfo& frameTimelineInfo, + nsecs_t postTime); // Creates a new handle each time, so we only expect // this to be called once. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c1fabf8322..2a1a4aa5b2 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3264,7 +3264,7 @@ bool SurfaceFlinger::flushTransactionQueues() { break; } transactions.push_back(transaction); - applyTransactionState(transaction.frameTimelineVsyncId, transaction.states, + applyTransactionState(transaction.frameTimelineInfo, transaction.states, transaction.displays, transaction.flags, mPendingInputWindowCommands, transaction.desiredPresentTime, transaction.isAutoTimestamp, transaction.buffer, @@ -3334,7 +3334,7 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, } status_t SurfaceFlinger::setTransactionState( - int64_t frameTimelineVsyncId, const Vector& states, + const FrameTimelineInfo& frameTimelineInfo, const Vector& states, const Vector& displays, uint32_t flags, const sp& applyToken, const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, @@ -3387,7 +3387,7 @@ status_t SurfaceFlinger::setTransactionState( // if the transaction contains a buffer. if (!transactionIsReadyToBeApplied(isAutoTimestamp ? 0 : desiredPresentTime, states, true) || pendingTransactions) { - mTransactionQueues[applyToken].emplace(frameTimelineVsyncId, states, displays, flags, + mTransactionQueues[applyToken].emplace(frameTimelineInfo, states, displays, flags, desiredPresentTime, isAutoTimestamp, uncacheBuffer, postTime, privileged, hasListenerCallbacks, listenerCallbacks, originPid, originUid, @@ -3396,7 +3396,7 @@ status_t SurfaceFlinger::setTransactionState( return NO_ERROR; } - applyTransactionState(frameTimelineVsyncId, states, displays, flags, inputWindowCommands, + applyTransactionState(frameTimelineInfo, states, displays, flags, inputWindowCommands, desiredPresentTime, isAutoTimestamp, uncacheBuffer, postTime, privileged, hasListenerCallbacks, listenerCallbacks, originPid, originUid, transactionId, /*isMainThread*/ false); @@ -3404,7 +3404,7 @@ status_t SurfaceFlinger::setTransactionState( } void SurfaceFlinger::applyTransactionState( - int64_t frameTimelineVsyncId, const Vector& states, + const FrameTimelineInfo& frameTimelineInfo, const Vector& states, const Vector& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, const int64_t postTime, @@ -3445,9 +3445,9 @@ void SurfaceFlinger::applyTransactionState( uint32_t clientStateFlags = 0; for (const ComposerState& state : states) { clientStateFlags |= - setClientStateLocked(frameTimelineVsyncId, state, desiredPresentTime, - isAutoTimestamp, postTime, privileged, - listenerCallbacksWithSurfaces, originPid, originUid); + setClientStateLocked(frameTimelineInfo, state, desiredPresentTime, isAutoTimestamp, + postTime, privileged, listenerCallbacksWithSurfaces, originPid, + originUid); if ((flags & eAnimation) && state.state.surface) { if (const auto layer = fromHandleLocked(state.state.surface).promote(); layer) { mScheduler->recordLayerHistory(layer.get(), @@ -3625,7 +3625,7 @@ bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermis } uint32_t SurfaceFlinger::setClientStateLocked( - int64_t frameTimelineVsyncId, const ComposerState& composerState, + const FrameTimelineInfo& frameTimelineInfo, const ComposerState& composerState, int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, bool privileged, std::unordered_set& listenerCallbacks, int originPid, int originUid) { @@ -3883,10 +3883,10 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTraversalNeeded; } } - if (what & layer_state_t::eFrameTimelineVsyncChanged) { - layer->setFrameTimelineVsyncForTransaction(s.frameTimelineVsyncId, postTime); - } else if (frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID) { - layer->setFrameTimelineVsyncForTransaction(frameTimelineVsyncId, postTime); + if (what & layer_state_t::eFrameTimelineInfoChanged) { + layer->setFrameTimelineInfoForTransaction(s.frameTimelineInfo, postTime); + } else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { + layer->setFrameTimelineInfoForTransaction(frameTimelineInfo, postTime); } if (what & layer_state_t::eFixedTransformHintChanged) { if (layer->setFixedTransformHint(s.fixedTransformHint)) { @@ -4222,7 +4222,7 @@ void SurfaceFlinger::onInitializeDisplays() { d.width = 0; d.height = 0; displays.add(d); - setTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, state, displays, 0, nullptr, + setTransactionState(FrameTimelineInfo{}, state, displays, 0, nullptr, mPendingInputWindowCommands, systemTime(), true, {}, false, {}, 0 /* Undefined transactionId */); @@ -4973,7 +4973,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case CAPTURE_LAYERS: case CAPTURE_DISPLAY: case SET_DISPLAY_BRIGHTNESS: - case SET_FRAME_TIMELINE_VSYNC: + case SET_FRAME_TIMELINE_INFO: // This is not sensitive information, so should not require permission control. case GET_GPU_CONTEXT_PRIORITY: { return OK; @@ -6350,21 +6350,21 @@ void SurfaceFlinger::onFrameRateFlexibilityTokenReleased() { })); } -status_t SurfaceFlinger::setFrameTimelineVsync(const sp& surface, - int64_t frameTimelineVsyncId) { +status_t SurfaceFlinger::setFrameTimelineInfo(const sp& surface, + const FrameTimelineInfo& frameTimelineInfo) { Mutex::Autolock lock(mStateLock); if (!authenticateSurfaceTextureLocked(surface)) { - ALOGE("Attempt to set frame timeline vsync on an unrecognized IGraphicBufferProducer"); + ALOGE("Attempt to set frame timeline info on an unrecognized IGraphicBufferProducer"); return BAD_VALUE; } sp layer = (static_cast(surface.get()))->getLayer(); if (layer == nullptr) { - ALOGE("Attempt to set frame timeline vsync on a layer that no longer exists"); + ALOGE("Attempt to set frame timeline info on a layer that no longer exists"); return BAD_VALUE; } - layer->setFrameTimelineVsyncForBuffer(frameTimelineVsyncId); + layer->setFrameTimelineInfoForBuffer(frameTimelineInfo); return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index c90fb4aca3..c54c1fb892 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -342,7 +342,7 @@ protected: virtual ~SurfaceFlinger(); virtual uint32_t setClientStateLocked( - int64_t frameTimelineVsyncId, const ComposerState& composerState, + const FrameTimelineInfo& info, const ComposerState& composerState, int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, bool privileged, std::unordered_set& listenerCallbacks, int originPid, int originUid) REQUIRES(mStateLock); @@ -434,14 +434,15 @@ private: }; struct TransactionState { - TransactionState(int64_t frameTimelineVsyncId, const Vector& composerStates, + TransactionState(const FrameTimelineInfo& frameTimelineInfo, + const Vector& composerStates, const Vector& displayStates, uint32_t transactionFlags, int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, int64_t postTime, bool privileged, bool hasListenerCallbacks, std::vector listenerCallbacks, int originPid, int originUid, uint64_t transactionId) - : frameTimelineVsyncId(frameTimelineVsyncId), + : frameTimelineInfo(frameTimelineInfo), states(composerStates), displays(displayStates), flags(transactionFlags), @@ -456,7 +457,7 @@ private: originUid(originUid), id(transactionId) {} - int64_t frameTimelineVsyncId; + FrameTimelineInfo frameTimelineInfo; Vector states; Vector displays; uint32_t flags; @@ -521,7 +522,8 @@ private: void destroyDisplay(const sp& displayToken) override; std::vector getPhysicalDisplayIds() const override; sp getPhysicalDisplayToken(PhysicalDisplayId displayId) const override; - status_t setTransactionState(int64_t frameTimelineVsyncId, const Vector& state, + status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo, + const Vector& state, const Vector& displays, uint32_t flags, const sp& applyToken, const InputWindowCommands& inputWindowCommands, @@ -607,8 +609,8 @@ private: int8_t compatibility, bool shouldBeSeamless) override; status_t acquireFrameRateFlexibilityToken(sp* outToken) override; - status_t setFrameTimelineVsync(const sp& surface, - int64_t frameTimelineVsyncId) override; + status_t setFrameTimelineInfo(const sp& surface, + const FrameTimelineInfo& frameTimelineInfo) override; status_t addTransactionTraceListener( const sp& listener) override; @@ -725,7 +727,7 @@ private: /* * Transactions */ - void applyTransactionState(int64_t frameTimelineVsyncId, const Vector& state, + void applyTransactionState(const FrameTimelineInfo& info, const Vector& state, const Vector& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, bool isAutoTimestamp, diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp index ecfed13adb..913f133a96 100644 --- a/services/surfaceflinger/tests/LayerState_test.cpp +++ b/services/surfaceflinger/tests/LayerState_test.cpp @@ -104,5 +104,34 @@ TEST(LayerStateTest, ParcellingScreenCaptureResults) { ASSERT_EQ(results.result, results2.result); } +/** + * Parcel a layer_state_t struct, and then unparcel. Ensure that the object that was parceled + * matches the object that's unparceled. + */ +TEST(LayerStateTest, ParcelUnparcelLayerStateT) { + layer_state_t input; + input.frameTimelineInfo.vsyncId = 1; + input.frameTimelineInfo.inputEventId = 2; + Parcel p; + input.write(p); + layer_state_t output; + p.setDataPosition(0); + output.read(p); + ASSERT_EQ(input.frameTimelineInfo.vsyncId, output.frameTimelineInfo.vsyncId); + ASSERT_EQ(input.frameTimelineInfo.inputEventId, output.frameTimelineInfo.inputEventId); +} + +TEST(LayerStateTest, LayerStateMerge_SelectsValidInputEvent) { + layer_state_t layer1; + layer1.frameTimelineInfo.inputEventId = android::os::IInputConstants::INVALID_INPUT_EVENT_ID; + layer_state_t layer2; + layer2.frameTimelineInfo.inputEventId = 1; + layer2.what |= layer_state_t::eFrameTimelineInfoChanged; + + layer1.merge(layer2); + + ASSERT_EQ(1, layer1.frameTimelineInfo.inputEventId); +} + } // namespace test } // namespace android diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp index e2584e266d..6e9f09bdaa 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -14,9 +14,6 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wextra" #include "gmock/gmock-spec-builders.h" #include "mock/MockTimeStats.h" @@ -177,16 +174,17 @@ static const std::string sLayerNameTwo = "layer2"; static constexpr const uid_t sUidOne = 0; static constexpr pid_t sPidOne = 10; static constexpr pid_t sPidTwo = 20; +static constexpr int32_t sInputEventId = 5; TEST_F(FrameTimelineTest, tokenManagerRemovesStalePredictions) { int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0}); - EXPECT_EQ(getPredictions().size(), 1); + EXPECT_EQ(getPredictions().size(), 1u); flushTokens(systemTime() + maxTokenRetentionTime); int64_t token2 = mTokenManager->generateTokenForPredictions({10, 20, 30}); std::optional predictions = mTokenManager->getPredictionsForToken(token1); // token1 should have expired - EXPECT_EQ(getPredictions().size(), 1); + EXPECT_EQ(getPredictions().size(), 1u); EXPECT_EQ(predictions.has_value(), false); predictions = mTokenManager->getPredictionsForToken(token2); @@ -194,16 +192,16 @@ TEST_F(FrameTimelineTest, tokenManagerRemovesStalePredictions) { } TEST_F(FrameTimelineTest, createSurfaceFrameForToken_getOwnerPidReturnsCorrectPid) { - auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne, + auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); - auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidTwo, sUidOne, + auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({}, sPidTwo, sUidOne, sLayerNameOne, sLayerNameOne); EXPECT_EQ(surfaceFrame1->getOwnerPid(), sPidOne); EXPECT_EQ(surfaceFrame2->getOwnerPid(), sPidTwo); } TEST_F(FrameTimelineTest, createSurfaceFrameForToken_noToken) { - auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne, + auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::None); } @@ -211,21 +209,33 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_noToken) { TEST_F(FrameTimelineTest, createSurfaceFrameForToken_expiredToken) { int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0}); flushTokens(systemTime() + maxTokenRetentionTime); - auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + auto surfaceFrame = + mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, + sLayerNameOne, sLayerNameOne); EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Expired); } TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validToken) { int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); - auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + auto surfaceFrame = + mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, + sLayerNameOne, sLayerNameOne); EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Valid); EXPECT_EQ(compareTimelineItems(surfaceFrame->getPredictions(), TimelineItem(10, 20, 30)), true); } +TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validInputEventId) { + int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); + constexpr int32_t inputEventId = 1; + auto surfaceFrame = + mFrameTimeline->createSurfaceFrameForToken({token1, inputEventId}, sPidOne, sUidOne, + sLayerNameOne, sLayerNameOne); + + EXPECT_EQ(inputEventId, surfaceFrame->getInputEventId()); +} + TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) { // Global increment EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)); @@ -234,8 +244,9 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) { int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); - auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + auto surfaceFrame1 = + mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, + sLayerNameOne, sLayerNameOne); // Set up the display frame mFrameTimeline->setSfWakeUp(token1, 20, 11); @@ -264,11 +275,11 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) { int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30}); int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 60}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameTwo, sLayerNameTwo); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameTwo, sLayerNameTwo); mFrameTimeline->setSfWakeUp(sfToken1, 22, 11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -288,8 +299,8 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) { // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto surfaceFrame3 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken2, 52, 11); surfaceFrame3->setPresentState(SurfaceFrame::PresentState::Dropped); mFrameTimeline->addSurfaceFrame(surfaceFrame3); @@ -320,8 +331,9 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { int64_t sfToken = mTokenManager->generateTokenForPredictions( {22 + frameTimeFactor, 26 + frameTimeFactor, 30 + frameTimeFactor}); auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, + sPidOne, sUidOne, sLayerNameOne, + sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); @@ -341,8 +353,8 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { int64_t sfToken = mTokenManager->generateTokenForPredictions( {22 + frameTimeFactor, 26 + frameTimeFactor, 30 + frameTimeFactor}); auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); @@ -356,18 +368,18 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { } TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceAfterQueue) { - auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, 0, - "acquireFenceAfterQueue", - "acquireFenceAfterQueue"); + auto surfaceFrame = + mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, 0, "acquireFenceAfterQueue", + "acquireFenceAfterQueue"); surfaceFrame->setActualQueueTime(123); surfaceFrame->setAcquireFenceTime(456); EXPECT_EQ(surfaceFrame->getActuals().endTime, 456); } TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceBeforeQueue) { - auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, 0, - "acquireFenceAfterQueue", - "acquireFenceAfterQueue"); + auto surfaceFrame = + mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, 0, "acquireFenceAfterQueue", + "acquireFenceAfterQueue"); surfaceFrame->setActualQueueTime(456); surfaceFrame->setAcquireFenceTime(123); EXPECT_EQ(surfaceFrame->getActuals().endTime, 456); @@ -383,8 +395,8 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { // Size shouldn't exceed maxDisplayFrames - 64 for (size_t i = 0; i < *maxDisplayFrames + 10; i++) { auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, + sLayerNameOne); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); mFrameTimeline->setSfWakeUp(sfToken, 22, 11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); @@ -395,15 +407,15 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { // Increase the size to 256 mFrameTimeline->setMaxDisplayFrames(256); - EXPECT_EQ(*maxDisplayFrames, 256); + EXPECT_EQ(*maxDisplayFrames, 256u); // Global increment EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)) .Times(static_cast(*maxDisplayFrames + 10)); for (size_t i = 0; i < *maxDisplayFrames + 10; i++) { auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, + sLayerNameOne); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); mFrameTimeline->setSfWakeUp(sfToken, 22, 11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); @@ -414,15 +426,15 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { // Shrink the size to 128 mFrameTimeline->setMaxDisplayFrames(128); - EXPECT_EQ(*maxDisplayFrames, 128); + EXPECT_EQ(*maxDisplayFrames, 128u); // Global increment EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)) .Times(static_cast(*maxDisplayFrames + 10)); for (size_t i = 0; i < *maxDisplayFrames + 10; i++) { auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, + sLayerNameOne); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); mFrameTimeline->setSfWakeUp(sfToken, 22, 11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); @@ -449,8 +461,8 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) { std::chrono::duration_cast(56ms).count(), std::chrono::duration_cast(60ms).count()}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::duration_cast(52ms).count(), 11); @@ -478,8 +490,8 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { std::chrono::duration_cast(56ms).count(), std::chrono::duration_cast(60ms).count()}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::duration_cast(52ms).count(), 30); @@ -507,8 +519,8 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) { std::chrono::duration_cast(86ms).count(), std::chrono::duration_cast(90ms).count()}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime( std::chrono::duration_cast(45ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, @@ -542,8 +554,9 @@ TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) { int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); - auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + auto surfaceFrame1 = + mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, + sLayerNameOne, sLayerNameOne); // Set up the display frame mFrameTimeline->setSfWakeUp(token1, 20, 11); @@ -558,7 +571,7 @@ TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) { mFrameTimeline->setSfPresent(55, presentFence2); auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); - EXPECT_EQ(packets.size(), 0); + EXPECT_EQ(packets.size(), 0u); } TEST_F(FrameTimelineTest, tracing_sanityTest) { @@ -573,8 +586,9 @@ TEST_F(FrameTimelineTest, tracing_sanityTest) { tracingSession->StartBlocking(); int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); - auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + auto surfaceFrame1 = + mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, + sLayerNameOne, sLayerNameOne); // Set up the display frame mFrameTimeline->setSfWakeUp(token2, 20, 11); @@ -594,7 +608,7 @@ TEST_F(FrameTimelineTest, tracing_sanityTest) { auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); // Display Frame 1 has 8 packets - 4 from DisplayFrame and 4 from SurfaceFrame. - EXPECT_EQ(packets.size(), 8); + EXPECT_EQ(packets.size(), 8u); } TEST_F(FrameTimelineTest, traceDisplayFrame_invalidTokenDoesNotEmitTracePacket) { @@ -622,7 +636,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_invalidTokenDoesNotEmitTracePacket) tracingSession->StopBlocking(); auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); - EXPECT_EQ(packets.size(), 0); + EXPECT_EQ(packets.size(), 0u); } TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) { @@ -635,7 +649,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) tracingSession->StartBlocking(); int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); - auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne, + auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); // Set up the display frame @@ -657,7 +671,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); // Display Frame 1 has 4 packets (SurfaceFrame shouldn't be traced since it has an invalid // token). - EXPECT_EQ(packets.size(), 4); + EXPECT_EQ(packets.size(), 4u); } void validateTraceEvent(const ProtoExpectedDisplayFrameStart& received, @@ -791,12 +805,12 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) { tracingSession->StopBlocking(); auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); - EXPECT_EQ(packets.size(), 4); + EXPECT_EQ(packets.size(), 4u); // Packet - 0 : ExpectedDisplayFrameStart const auto& packet0 = packets[0]; ASSERT_TRUE(packet0.has_timestamp()); - EXPECT_EQ(packet0.timestamp(), 10); + EXPECT_EQ(packet0.timestamp(), 10u); ASSERT_TRUE(packet0.has_frame_timeline_event()); const auto& event0 = packet0.frame_timeline_event(); @@ -807,7 +821,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) { // Packet - 1 : FrameEnd (ExpectedDisplayFrame) const auto& packet1 = packets[1]; ASSERT_TRUE(packet1.has_timestamp()); - EXPECT_EQ(packet1.timestamp(), 25); + EXPECT_EQ(packet1.timestamp(), 25u); ASSERT_TRUE(packet1.has_frame_timeline_event()); const auto& event1 = packet1.frame_timeline_event(); @@ -818,7 +832,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) { // Packet - 2 : ActualDisplayFrameStart const auto& packet2 = packets[2]; ASSERT_TRUE(packet2.has_timestamp()); - EXPECT_EQ(packet2.timestamp(), 20); + EXPECT_EQ(packet2.timestamp(), 20u); ASSERT_TRUE(packet2.has_frame_timeline_event()); const auto& event2 = packet2.frame_timeline_event(); @@ -829,7 +843,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) { // Packet - 3 : FrameEnd (ActualDisplayFrame) const auto& packet3 = packets[3]; ASSERT_TRUE(packet3.has_timestamp()); - EXPECT_EQ(packet3.timestamp(), 26); + EXPECT_EQ(packet3.timestamp(), 26u); ASSERT_TRUE(packet3.has_frame_timeline_event()); const auto& event3 = packet3.frame_timeline_event(); @@ -853,8 +867,8 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { int64_t displayFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setActualStartTime(0); surfaceFrame1->setActualQueueTime(15); surfaceFrame1->setAcquireFenceTime(20); @@ -904,12 +918,12 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { tracingSession->StopBlocking(); auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); - EXPECT_EQ(packets.size(), 8); + EXPECT_EQ(packets.size(), 8u); // Packet - 4 : ExpectedSurfaceFrameStart const auto& packet4 = packets[4]; ASSERT_TRUE(packet4.has_timestamp()); - EXPECT_EQ(packet4.timestamp(), 10); + EXPECT_EQ(packet4.timestamp(), 10u); ASSERT_TRUE(packet4.has_frame_timeline_event()); const auto& event4 = packet4.frame_timeline_event(); @@ -920,7 +934,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { // Packet - 5 : FrameEnd (ExpectedSurfaceFrame) const auto& packet5 = packets[5]; ASSERT_TRUE(packet5.has_timestamp()); - EXPECT_EQ(packet5.timestamp(), 25); + EXPECT_EQ(packet5.timestamp(), 25u); ASSERT_TRUE(packet5.has_frame_timeline_event()); const auto& event5 = packet5.frame_timeline_event(); @@ -931,7 +945,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { // Packet - 6 : ActualSurfaceFrameStart const auto& packet6 = packets[6]; ASSERT_TRUE(packet6.has_timestamp()); - EXPECT_EQ(packet6.timestamp(), 10); + EXPECT_EQ(packet6.timestamp(), 10u); ASSERT_TRUE(packet6.has_frame_timeline_event()); const auto& event6 = packet6.frame_timeline_event(); @@ -942,7 +956,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { // Packet - 7 : FrameEnd (ActualSurfaceFrame) const auto& packet7 = packets[7]; ASSERT_TRUE(packet7.has_timestamp()); - EXPECT_EQ(packet7.timestamp(), 20); + EXPECT_EQ(packet7.timestamp(), 20u); ASSERT_TRUE(packet7.has_frame_timeline_event()); const auto& event7 = packet7.frame_timeline_event(); @@ -961,8 +975,8 @@ TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) { int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30}); auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken1, 22, 11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); @@ -1126,8 +1140,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40}); int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(16); mFrameTimeline->setSfWakeUp(sfToken1, 22, 11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1145,8 +1159,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame2->setAcquireFenceTime(36); mFrameTimeline->setSfWakeUp(sfToken2, 52, 11); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1199,8 +1213,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40}); int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(16); mFrameTimeline->setSfWakeUp(sfToken1, 22, 11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1218,8 +1232,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame2->setAcquireFenceTime(36); mFrameTimeline->setSfWakeUp(sfToken2, 52, 11); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1270,8 +1284,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishEarlyPresent) int64_t sfToken1 = mTokenManager->generateTokenForPredictions({42, 46, 50}); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 26, 60}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken1, 42, 11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1316,8 +1330,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 30}); int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 50}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(26); mFrameTimeline->setSfWakeUp(sfToken1, 32, 11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1335,8 +1349,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame2->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken2, 43, 11); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1390,8 +1404,8 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 56, 60}); int64_t sfToken2 = mTokenManager->generateTokenForPredictions({112, 116, 120}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(50); mFrameTimeline->setSfWakeUp(sfToken1, 52, 30); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1409,8 +1423,8 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame2->setAcquireFenceTime(84); mFrameTimeline->setSfWakeUp(sfToken2, 112, 30); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented, 54); @@ -1456,6 +1470,3 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli JankType::AppDeadlineMissed | JankType::BufferStuffing); } } // namespace android::frametimeline - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 9a9eeab96c..a46affd4a3 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -368,16 +368,14 @@ public: auto& getTransactionQueue() { return mFlinger->mTransactionQueues; } - auto setTransactionState(int64_t frameTimelineVsyncId, const Vector& states, - const Vector& displays, uint32_t flags, - const sp& applyToken, - const InputWindowCommands& inputWindowCommands, - int64_t desiredPresentTime, bool isAutoTimestamp, - const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, - std::vector& listenerCallbacks, - uint64_t transactionId) { - return mFlinger->setTransactionState(frameTimelineVsyncId, states, displays, flags, - applyToken, inputWindowCommands, desiredPresentTime, + auto setTransactionState( + const FrameTimelineInfo& frameTimelineInfo, const Vector& states, + const Vector& displays, uint32_t flags, const sp& applyToken, + const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, + bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, + std::vector& listenerCallbacks, uint64_t transactionId) { + return mFlinger->setTransactionState(frameTimelineInfo, states, displays, flags, applyToken, + inputWindowCommands, desiredPresentTime, isAutoTimestamp, uncacheBuffer, hasListenerCallbacks, listenerCallbacks, transactionId); } diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index 06275c6b5b..6d2f672bce 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -14,10 +14,6 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#pragma clang diagnostic ignored "-Wextra" #undef LOG_TAG #define LOG_TAG "CompositionTest" @@ -100,43 +96,44 @@ public: InputWindowCommands inputWindowCommands; int64_t desiredPresentTime = 0; bool isAutoTimestamp = true; - int64_t frameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; + FrameTimelineInfo frameTimelineInfo; client_cache_t uncacheBuffer; - int64_t id = -1; + uint64_t id = static_cast(-1); + static_assert(0xffffffffffffffff == static_cast(-1)); }; void checkEqual(TransactionInfo info, SurfaceFlinger::TransactionState state) { - EXPECT_EQ(0, info.states.size()); - EXPECT_EQ(0, state.states.size()); + EXPECT_EQ(0u, info.states.size()); + EXPECT_EQ(0u, state.states.size()); - EXPECT_EQ(0, info.displays.size()); - EXPECT_EQ(0, state.displays.size()); + EXPECT_EQ(0u, info.displays.size()); + EXPECT_EQ(0u, state.displays.size()); EXPECT_EQ(info.flags, state.flags); EXPECT_EQ(info.desiredPresentTime, state.desiredPresentTime); } void setupSingle(TransactionInfo& transaction, uint32_t flags, bool syncInputWindows, int64_t desiredPresentTime, bool isAutoTimestamp, - int64_t frameTimelineVsyncId) { + const FrameTimelineInfo& frameTimelineInfo) { mTransactionNumber++; transaction.flags |= flags; // ISurfaceComposer::eSynchronous; transaction.inputWindowCommands.syncInputWindows = syncInputWindows; transaction.desiredPresentTime = desiredPresentTime; transaction.isAutoTimestamp = isAutoTimestamp; - transaction.frameTimelineVsyncId = frameTimelineVsyncId; + transaction.frameTimelineInfo = frameTimelineInfo; } void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) { - ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillOnce(Return(systemTime())); TransactionInfo transaction; setupSingle(transaction, flags, syncInputWindows, /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, - ISurfaceComposer::INVALID_VSYNC_ID); + FrameTimelineInfo{}); nsecs_t applicationTime = systemTime(); - mFlinger.setTransactionState(transaction.frameTimelineVsyncId, transaction.states, + mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states, transaction.displays, transaction.flags, transaction.applyToken, transaction.inputWindowCommands, transaction.desiredPresentTime, transaction.isAutoTimestamp, @@ -155,11 +152,11 @@ public: EXPECT_LE(returnedTime, applicationTime + s2ns(5)); } auto transactionQueue = mFlinger.getTransactionQueue(); - EXPECT_EQ(0, transactionQueue.size()); + EXPECT_EQ(0u, transactionQueue.size()); } void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) { - ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); @@ -170,10 +167,9 @@ public: .WillOnce(Return(time + nsecs_t(5 * 1e8))); TransactionInfo transaction; setupSingle(transaction, flags, syncInputWindows, - /*desiredPresentTime*/ time + s2ns(1), false, - ISurfaceComposer::INVALID_VSYNC_ID); + /*desiredPresentTime*/ time + s2ns(1), false, FrameTimelineInfo{}); nsecs_t applicationSentTime = systemTime(); - mFlinger.setTransactionState(transaction.frameTimelineVsyncId, transaction.states, + mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states, transaction.displays, transaction.flags, transaction.applyToken, transaction.inputWindowCommands, transaction.desiredPresentTime, transaction.isAutoTimestamp, @@ -184,11 +180,11 @@ public: EXPECT_LE(returnedTime, applicationSentTime + s2ns(5)); // This transaction should have been placed on the transaction queue auto transactionQueue = mFlinger.getTransactionQueue(); - EXPECT_EQ(1, transactionQueue.size()); + EXPECT_EQ(1u, transactionQueue.size()); } void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) { - ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction nsecs_t time = systemTime(); EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); @@ -197,18 +193,17 @@ public: // transaction that should go on the pending thread TransactionInfo transactionA; setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false, - /*desiredPresentTime*/ time + s2ns(1), false, - ISurfaceComposer::INVALID_VSYNC_ID); + /*desiredPresentTime*/ time + s2ns(1), false, FrameTimelineInfo{}); // transaction that would not have gone on the pending thread if not // blocked TransactionInfo transactionB; setupSingle(transactionB, flags, syncInputWindows, /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, - ISurfaceComposer::INVALID_VSYNC_ID); + FrameTimelineInfo{}); nsecs_t applicationSentTime = systemTime(); - mFlinger.setTransactionState(transactionA.frameTimelineVsyncId, transactionA.states, + mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, transactionA.displays, transactionA.flags, transactionA.applyToken, transactionA.inputWindowCommands, transactionA.desiredPresentTime, transactionA.isAutoTimestamp, @@ -221,7 +216,7 @@ public: EXPECT_LE(systemTime(), applicationSentTime + s2ns(5)); applicationSentTime = systemTime(); - mFlinger.setTransactionState(transactionB.frameTimelineVsyncId, transactionB.states, + mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states, transactionB.displays, transactionB.flags, transactionB.applyToken, transactionB.inputWindowCommands, transactionB.desiredPresentTime, transactionB.isAutoTimestamp, @@ -240,10 +235,10 @@ public: // check that there is one binder on the pending queue. auto transactionQueue = mFlinger.getTransactionQueue(); - EXPECT_EQ(1, transactionQueue.size()); + EXPECT_EQ(1u, transactionQueue.size()); auto& [applyToken, transactionStates] = *(transactionQueue.begin()); - EXPECT_EQ(2, transactionStates.size()); + EXPECT_EQ(2u, transactionStates.size()); auto& transactionStateA = transactionStates.front(); transactionStates.pop(); @@ -258,7 +253,7 @@ public: }; TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { - ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); @@ -268,18 +263,18 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { .WillOnce(Return(s2ns(2))); TransactionInfo transactionA; // transaction to go on pending queue setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false, - /*desiredPresentTime*/ s2ns(1), false, ISurfaceComposer::INVALID_VSYNC_ID); - mFlinger.setTransactionState(transactionA.frameTimelineVsyncId, transactionA.states, + /*desiredPresentTime*/ s2ns(1), false, FrameTimelineInfo{}); + mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, transactionA.displays, transactionA.flags, transactionA.applyToken, transactionA.inputWindowCommands, transactionA.desiredPresentTime, transactionA.isAutoTimestamp, transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks, transactionA.id); auto& transactionQueue = mFlinger.getTransactionQueue(); - ASSERT_EQ(1, transactionQueue.size()); + ASSERT_EQ(1u, transactionQueue.size()); auto& [applyToken, transactionStates] = *(transactionQueue.begin()); - ASSERT_EQ(1, transactionStates.size()); + ASSERT_EQ(1u, transactionStates.size()); auto& transactionState = transactionStates.front(); checkEqual(transactionA, transactionState); @@ -289,8 +284,8 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { // different process) to re-query and reset the cached expected present time TransactionInfo empty; empty.applyToken = sp(); - mFlinger.setTransactionState(empty.frameTimelineVsyncId, empty.states, empty.displays, - empty.flags, empty.applyToken, empty.inputWindowCommands, + mFlinger.setTransactionState(empty.frameTimelineInfo, empty.states, empty.displays, empty.flags, + empty.applyToken, empty.inputWindowCommands, empty.desiredPresentTime, empty.isAutoTimestamp, empty.uncacheBuffer, mHasListenerCallbacks, mCallbacks, empty.id); @@ -298,7 +293,7 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { // passed mFlinger.flushTransactionQueues(); - EXPECT_EQ(0, transactionQueue.size()); + EXPECT_EQ(0u, transactionQueue.size()); } TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Synchronous) { @@ -343,6 +338,3 @@ TEST_F(TransactionApplicationTest, FromHandle) { EXPECT_EQ(nullptr, ret.promote().get()); } } // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" -- cgit v1.2.3-59-g8ed1b From 4d08ae78c2654f198264ae4a85cc7686dff46291 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 26 Jan 2021 14:55:48 -0800 Subject: Remove __ANDROID_API__ #if checks. __INTRODUCED_IN() does the right thing automatically now. Bug: http://b/178449269 Test: treehugger Change-Id: I94d2ad6fafb6d907793a416db82a9e56f4f61d1c --- include/android/bitmap.h | 8 ------ include/android/choreographer.h | 11 -------- include/android/configuration.h | 4 --- include/android/font.h | 4 --- include/android/font_matcher.h | 4 --- include/android/imagedecoder.h | 32 ---------------------- include/android/multinetwork.h | 8 ------ include/android/native_window_jni.h | 2 -- include/android/sensor.h | 27 ++++++------------ include/android/sharedmem.h | 4 --- include/android/sharedmem_jni.h | 4 --- include/android/surface_control.h | 11 -------- include/android/surface_texture.h | 4 --- include/android/surface_texture_jni.h | 4 --- include/android/system_fonts.h | 4 --- include/android/trace.h | 8 ------ .../nativewindow/include/android/hardware_buffer.h | 11 -------- libs/nativewindow/include/android/native_window.h | 18 +----------- 18 files changed, 9 insertions(+), 159 deletions(-) diff --git a/include/android/bitmap.h b/include/android/bitmap.h index d7f25e1858..2362c9e491 100644 --- a/include/android/bitmap.h +++ b/include/android/bitmap.h @@ -132,8 +132,6 @@ typedef struct { int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, AndroidBitmapInfo* info); -#if __ANDROID_API__ >= 30 - /** * Given a java bitmap object, return its {@link ADataSpace}. * @@ -145,8 +143,6 @@ int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, */ int32_t AndroidBitmap_getDataSpace(JNIEnv* env, jobject jbitmap) __INTRODUCED_IN(30); -#endif // __ANDROID_API__ >= 30 - /** * Given a java bitmap object, attempt to lock the pixel address. * Locking will ensure that the memory for the pixels will not move @@ -216,8 +212,6 @@ typedef bool (*AndroidBitmap_CompressWriteFunc)(void* userContext, const void* data, size_t size) __INTRODUCED_IN(30); -#if __ANDROID_API__ >= 30 - /** * Compress |pixels| as described by |info|. * @@ -269,8 +263,6 @@ typedef struct AHardwareBuffer AHardwareBuffer; int AndroidBitmap_getHardwareBuffer(JNIEnv* env, jobject bitmap, AHardwareBuffer** outBuffer) __INTRODUCED_IN(30); -#endif // __ANDROID_API__ >= 30 - #ifdef __cplusplus } #endif diff --git a/include/android/choreographer.h b/include/android/choreographer.h index e9f559cd8e..8039bb0d79 100644 --- a/include/android/choreographer.h +++ b/include/android/choreographer.h @@ -61,8 +61,6 @@ typedef void (*AChoreographer_frameCallback64)(int64_t frameTimeNanos, void* dat */ typedef void (*AChoreographer_refreshRateCallback)(int64_t vsyncPeriodNanos, void* data); -#if __ANDROID_API__ >= 24 - /** * Get the AChoreographer instance for the current thread. This must be called * on an ALooper thread. @@ -86,10 +84,6 @@ void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer, long delayMillis) __INTRODUCED_IN(24) __DEPRECATED_IN(29); -#endif /* __ANDROID_API__ >= 24 */ - -#if __ANDROID_API__ >= 29 - /** * Power a callback to be run on the next frame. The data pointer provided will * be passed to the callback function when it's called. @@ -111,10 +105,6 @@ void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer, AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) __INTRODUCED_IN(29); -#endif /* __ANDROID_API__ >= 29 */ - -#if __ANDROID_API__ >= 30 - /** * Registers a callback to be run when the display refresh rate changes. The * data pointer provided will be passed to the callback function when it's @@ -160,7 +150,6 @@ void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer, void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer, AChoreographer_refreshRateCallback, void* data) __INTRODUCED_IN(30); -#endif /* __ANDROID_API__ >= 30 */ __END_DECLS diff --git a/include/android/configuration.h b/include/android/configuration.h index ccf3e59066..88019ae054 100644 --- a/include/android/configuration.h +++ b/include/android/configuration.h @@ -645,14 +645,12 @@ int32_t AConfiguration_getScreenLong(AConfiguration* config); */ void AConfiguration_setScreenLong(AConfiguration* config, int32_t screenLong); -#if __ANDROID_API__ >= 30 /** * Return the current ACONFIGURATION_SCREENROUND_* set in the configuration. * * Available since API level 30. */ int32_t AConfiguration_getScreenRound(AConfiguration* config) __INTRODUCED_IN(30); -#endif /** * Set the current screen round in the configuration. @@ -712,7 +710,6 @@ int32_t AConfiguration_getSmallestScreenWidthDp(AConfiguration* config); */ void AConfiguration_setSmallestScreenWidthDp(AConfiguration* config, int32_t value); -#if __ANDROID_API__ >= 17 /** * Return the configuration's layout direction, or * ACONFIGURATION_LAYOUTDIR_ANY if not set. @@ -727,7 +724,6 @@ int32_t AConfiguration_getLayoutDirection(AConfiguration* config) __INTRODUCED_I * Available since API level 17. */ void AConfiguration_setLayoutDirection(AConfiguration* config, int32_t value) __INTRODUCED_IN(17); -#endif /* __ANDROID_API__ >= 17 */ /** * Perform a diff between two configurations. Returns a bit mask of diff --git a/include/android/font.h b/include/android/font.h index 1618096d69..a172618829 100644 --- a/include/android/font.h +++ b/include/android/font.h @@ -51,8 +51,6 @@ __BEGIN_DECLS -#if __ANDROID_API__ >= 29 - enum { /** The minimum value fot the font weight value. */ AFONT_WEIGHT_MIN = 0, @@ -297,8 +295,6 @@ uint32_t AFont_getAxisTag(const AFont* _Nonnull font, uint32_t axisIndex) float AFont_getAxisValue(const AFont* _Nonnull font, uint32_t axisIndex) __INTRODUCED_IN(29); -#endif // __ANDROID_API__ >= 29 - __END_DECLS #endif // ANDROID_FONT_H diff --git a/include/android/font_matcher.h b/include/android/font_matcher.h index d4bd892bf6..49e478c2f3 100644 --- a/include/android/font_matcher.h +++ b/include/android/font_matcher.h @@ -97,8 +97,6 @@ __BEGIN_DECLS -#if __ANDROID_API__ >= 29 - enum { /** A family variant value for the system default variant. */ AFAMILY_VARIANT_DEFAULT = 0, @@ -217,8 +215,6 @@ AFont* _Nonnull AFontMatcher_match( const uint32_t textLength, uint32_t* _Nullable runLengthOut) __INTRODUCED_IN(29); -#endif // __ANDROID_API__ >= 29 - __END_DECLS #endif // ANDROID_FONT_MATCHER_H diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h index c7a8939766..819a6a4c1f 100644 --- a/include/android/imagedecoder.h +++ b/include/android/imagedecoder.h @@ -139,8 +139,6 @@ enum { ANDROID_IMAGE_DECODER_INVALID_STATE = -11, }; -#if __ANDROID_API__ >= 31 - /** * Return a constant string value representing the error code. * @@ -155,8 +153,6 @@ enum { */ const char* _Nullable AImageDecoder_resultToString(int)__INTRODUCED_IN(31); -#endif // __ANDROID_API__ >= 31 - struct AImageDecoder; /** @@ -179,8 +175,6 @@ struct AImageDecoder; */ typedef struct AImageDecoder AImageDecoder; -#if __ANDROID_API__ >= 30 - /** * Create a new {@link AImageDecoder} from an {@link AAsset}. * @@ -469,8 +463,6 @@ int AImageDecoder_computeSampledSize(const AImageDecoder* _Nonnull decoder, int */ int AImageDecoder_setCrop(AImageDecoder* _Nonnull decoder, ARect crop) __INTRODUCED_IN(30); -#endif // __ANDROID_API__ >= 30 - struct AImageDecoderHeaderInfo; /** * Opaque handle for representing information about the encoded image. @@ -483,8 +475,6 @@ struct AImageDecoderHeaderInfo; */ typedef struct AImageDecoderHeaderInfo AImageDecoderHeaderInfo; -#if __ANDROID_API__ >= 30 - /** * Return an opaque handle for reading header info. * @@ -672,10 +662,6 @@ int AImageDecoder_decodeImage(AImageDecoder* _Nonnull decoder, void* _Nonnull pixels, size_t stride, size_t size) __INTRODUCED_IN(30); -#endif // __ANDROID_API__ >= 30 - -#if __ANDROID_API__ >= 31 - /** * Return true iff the image is animated - i.e. has multiple frames. * @@ -690,8 +676,6 @@ int AImageDecoder_decodeImage(AImageDecoder* _Nonnull decoder, bool AImageDecoder_isAnimated(AImageDecoder* _Nonnull decoder) __INTRODUCED_IN(31); -#endif // __ANDROID_API__ >= 31 - enum { /* * Reported by {@link AImageDecoder_getRepeatCount} if the @@ -702,8 +686,6 @@ enum { ANDROID_IMAGE_DECODER_INFINITE = INT32_MAX, }; -#if __ANDROID_API__ >= 31 - /** * Report how many times the animation should repeat. * @@ -793,8 +775,6 @@ int AImageDecoder_advanceFrame(AImageDecoder* _Nonnull decoder) int AImageDecoder_rewind(AImageDecoder* _Nonnull decoder) __INTRODUCED_IN(31); -#endif // __ANDROID_API__ >= 31 - struct AImageDecoderFrameInfo; /** @@ -810,8 +790,6 @@ struct AImageDecoderFrameInfo; */ typedef struct AImageDecoderFrameInfo AImageDecoderFrameInfo; -#if __ANDROID_API__ >= 31 - /** * Create an uninitialized AImageDecoderFrameInfo. * @@ -922,8 +900,6 @@ ARect AImageDecoderFrameInfo_getFrameRect( bool AImageDecoderFrameInfo_hasAlphaWithinBounds( const AImageDecoderFrameInfo* _Nonnull info) __INTRODUCED_IN(31); -#endif // __ANDROID_API__ >= 31 - /** * How a frame is “disposed” before showing the next one. * @@ -947,8 +923,6 @@ enum { ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS = 3, }; -#if __ANDROID_API__ >= 31 - /** * Return how this frame is “disposed” before showing the next one. * @@ -969,8 +943,6 @@ enum { int32_t AImageDecoderFrameInfo_getDisposeOp( const AImageDecoderFrameInfo* _Nonnull info) __INTRODUCED_IN(31); -#endif // __ANDROID_API__ >= 31 - /** * How a frame is blended with the previous frame. * @@ -989,8 +961,6 @@ enum { ANDROID_IMAGE_DECODER_BLEND_OP_SRC_OVER = 2, }; -#if __ANDROID_API__ >= 31 - /** * Return how this frame is blended with the previous frame. * @@ -1047,8 +1017,6 @@ void AImageDecoder_setInternallyHandleDisposePrevious( __INTRODUCED_IN(31); -#endif // __ANDROID_API__ >= 31 - #ifdef __cplusplus } #endif diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h index c6d1c94c0a..424299d664 100644 --- a/include/android/multinetwork.h +++ b/include/android/multinetwork.h @@ -60,8 +60,6 @@ typedef uint64_t net_handle_t; * on failure with an appropriate errno value set. */ -#if __ANDROID_API__ >= 23 - /** * Set the network to be used by the given socket file descriptor. * @@ -111,10 +109,6 @@ int android_getaddrinfofornetwork(net_handle_t network, const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) __INTRODUCED_IN(23); -#endif /* __ANDROID_API__ >= 23 */ - -#if __ANDROID_API__ >= 29 - /** * Possible values of the flags argument to android_res_nsend and android_res_nquery. * Values are ORed together. @@ -187,8 +181,6 @@ int android_res_nresult(int fd, */ void android_res_cancel(int nsend_fd) __INTRODUCED_IN(29); -#endif /* __ANDROID_API__ >= 29 */ - __END_DECLS #endif // ANDROID_MULTINETWORK_H diff --git a/include/android/native_window_jni.h b/include/android/native_window_jni.h index 3a77ffe86b..071ec798b4 100644 --- a/include/android/native_window_jni.h +++ b/include/android/native_window_jni.h @@ -44,7 +44,6 @@ extern "C" { */ ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface); -#if __ANDROID_API__ >= 26 /** * Return a Java Surface object derived from the ANativeWindow, for interacting * with it through Java code. The returned Java object acquires a reference on @@ -55,7 +54,6 @@ ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface); * Available since API level 26. */ jobject ANativeWindow_toSurface(JNIEnv* env, ANativeWindow* window) __INTRODUCED_IN(26); -#endif #ifdef __cplusplus }; diff --git a/include/android/sensor.h b/include/android/sensor.h index eb407794d1..6447844b06 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -52,6 +52,13 @@ #include #include +#if !defined(__INTRODUCED_IN) +#define __INTRODUCED_IN(__api_level) /* nothing */ +#endif +#if !defined(__DEPRECATED_IN) +#define __DEPRECATED_IN(__api_level) __attribute__((__deprecated__)) +#endif + #ifdef __cplusplus extern "C" { #endif @@ -553,13 +560,8 @@ typedef ASensorRef const* ASensorList; * ASensorManager* sensorManager = ASensorManager_getInstance(); * */ -#if __ANDROID_API__ >= 26 -__attribute__ ((deprecated)) ASensorManager* ASensorManager_getInstance(); -#else -ASensorManager* ASensorManager_getInstance(); -#endif +ASensorManager* ASensorManager_getInstance() __DEPRECATED_IN(26); -#if __ANDROID_API__ >= 26 /** * Get a reference to the sensor manager. ASensorManager is a singleton * per package as different packages may have access to different sensors. @@ -571,7 +573,6 @@ ASensorManager* ASensorManager_getInstance(); * Available since API level 26. */ ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName) __INTRODUCED_IN(26); -#endif /** * Returns the list of available sensors. @@ -584,7 +585,6 @@ int ASensorManager_getSensorList(ASensorManager* manager, ASensorList* list); */ ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type); -#if __ANDROID_API__ >= 21 /** * Returns the default sensor with the given type and wakeUp properties or NULL if no sensor * of this type and wakeUp properties exists. @@ -592,7 +592,6 @@ ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type * Available since API level 21. */ ASensor const* ASensorManager_getDefaultSensorEx(ASensorManager* manager, int type, bool wakeUp) __INTRODUCED_IN(21); -#endif /** * Creates a new sensor event queue and associate it with a looper. @@ -609,7 +608,6 @@ ASensorEventQueue* ASensorManager_createEventQueue(ASensorManager* manager, */ int ASensorManager_destroyEventQueue(ASensorManager* manager, ASensorEventQueue* queue); -#if __ANDROID_API__ >= 26 /** * Create direct channel based on shared memory * @@ -706,7 +704,6 @@ void ASensorManager_destroyDirectChannel(ASensorManager* manager, int channelId) */ int ASensorManager_configureDirectReport(ASensorManager* manager, ASensor const* sensor, int channelId, int rate) __INTRODUCED_IN(26); -#endif /* __ANDROID_API__ >= 26 */ /*****************************************************************************/ @@ -795,7 +792,6 @@ int ASensorEventQueue_hasEvents(ASensorEventQueue* queue); */ ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* events, size_t count); -#if __ANDROID_API__ >= 29 /** * Request that {@link ASENSOR_TYPE_ADDITIONAL_INFO} events to be delivered on * the given {@link ASensorEventQueue}. @@ -819,7 +815,6 @@ ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* even * \return 0 on success or a negative error code on failure */ int ASensorEventQueue_requestAdditionalInfoEvents(ASensorEventQueue* queue, bool enable) __INTRODUCED_IN(29); -#endif /* __ANDROID_API__ >= 29 */ /*****************************************************************************/ @@ -850,7 +845,6 @@ float ASensor_getResolution(ASensor const* sensor); */ int ASensor_getMinDelay(ASensor const* sensor); -#if __ANDROID_API__ >= 21 /** * Returns the maximum size of batches for this sensor. Batches will often be * smaller, as the hardware fifo might be used for other sensors. @@ -886,9 +880,7 @@ int ASensor_getReportingMode(ASensor const* sensor) __INTRODUCED_IN(21); * Available since API level 21. */ bool ASensor_isWakeUpSensor(ASensor const* sensor) __INTRODUCED_IN(21); -#endif /* __ANDROID_API__ >= 21 */ -#if __ANDROID_API__ >= 26 /** * Test if sensor supports a certain type of direct channel. * @@ -914,9 +906,7 @@ bool ASensor_isDirectChannelTypeSupported(ASensor const* sensor, int channelType * does not support direct report. */ int ASensor_getHighestDirectReportRateLevel(ASensor const* sensor) __INTRODUCED_IN(26); -#endif /* __ANDROID_API__ >= 26 */ -#if __ANDROID_API__ >= 29 /** * Returns the sensor's handle. * @@ -934,7 +924,6 @@ int ASensor_getHighestDirectReportRateLevel(ASensor const* sensor) __INTRODUCED_ * Available since API level 29. */ int ASensor_getHandle(ASensor const* sensor) __INTRODUCED_IN(29); -#endif /* __ANDROID_API__ >= 29 */ #ifdef __cplusplus }; diff --git a/include/android/sharedmem.h b/include/android/sharedmem.h index 5f74682b40..7994aa9914 100644 --- a/include/android/sharedmem.h +++ b/include/android/sharedmem.h @@ -50,8 +50,6 @@ extern "C" { #endif -#if __ANDROID_API__ >= 26 - /** * Create a shared memory region. * @@ -121,8 +119,6 @@ size_t ASharedMemory_getSize(int fd) __INTRODUCED_IN(26); */ int ASharedMemory_setProt(int fd, int prot) __INTRODUCED_IN(26); -#endif // __ANDROID_API__ >= 26 - #ifdef __cplusplus }; #endif diff --git a/include/android/sharedmem_jni.h b/include/android/sharedmem_jni.h index 13e56e6f09..bbac785a33 100644 --- a/include/android/sharedmem_jni.h +++ b/include/android/sharedmem_jni.h @@ -52,8 +52,6 @@ extern "C" { #endif -#if __ANDROID_API__ >= 27 - /** * Returns a dup'd FD from the given Java android.os.SharedMemory object. The returned file * descriptor has all the same properties & capabilities as the FD returned from @@ -72,8 +70,6 @@ extern "C" { */ int ASharedMemory_dupFromJava(JNIEnv* env, jobject sharedMemory) __INTRODUCED_IN(27); -#endif // __ANDROID_API__ >= 27 - #ifdef __cplusplus }; #endif diff --git a/include/android/surface_control.h b/include/android/surface_control.h index 7a7424833b..98fd875968 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -35,8 +35,6 @@ __BEGIN_DECLS -#if __ANDROID_API__ >= 29 - struct ASurfaceControl; /** @@ -409,10 +407,6 @@ void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transactio struct AHdrMetadata_cta861_3* metadata) __INTRODUCED_IN(29); -#endif // __ANDROID_API__ >= 29 - -#if __ANDROID_API__ >= 30 - /** * Same as ASurfaceTransaction_setFrameRateWithSeamlessness(transaction, surface_control, * frameRate, compatibility, true). @@ -425,10 +419,6 @@ void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, float frameRate, int8_t compatibility) __INTRODUCED_IN(30); -#endif // __ANDROID_API__ >= 30 - -#if __ANDROID_API__ >= 31 - /** * Sets the intended frame rate for \a surface_control. * @@ -462,7 +452,6 @@ void ASurfaceTransaction_setFrameRateWithSeamlessness(ASurfaceTransaction* trans int8_t compatibility, bool shouldBeSeamless) __INTRODUCED_IN(31); -#endif // __ANDROID_API__ >= 31 __END_DECLS #endif // ANDROID_SURFACE_CONTROL_H diff --git a/include/android/surface_texture.h b/include/android/surface_texture.h index dde7eaa0b6..b227b324f8 100644 --- a/include/android/surface_texture.h +++ b/include/android/surface_texture.h @@ -59,8 +59,6 @@ struct ASurfaceTexture; */ typedef struct ASurfaceTexture ASurfaceTexture; -#if __ANDROID_API__ >= 28 - /** * Release the reference to the native ASurfaceTexture acquired with * ASurfaceTexture_fromSurfaceTexture(). @@ -175,8 +173,6 @@ void ASurfaceTexture_getTransformMatrix(ASurfaceTexture* st, float mtx[16]) __IN */ int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st) __INTRODUCED_IN(28); -#endif /* __ANDROID_API__ >= 28 */ - __END_DECLS #endif /* ANDROID_NATIVE_SURFACE_TEXTURE_H */ diff --git a/include/android/surface_texture_jni.h b/include/android/surface_texture_jni.h index 2266d541f6..e40686d96c 100644 --- a/include/android/surface_texture_jni.h +++ b/include/android/surface_texture_jni.h @@ -32,8 +32,6 @@ __BEGIN_DECLS -#if __ANDROID_API__ >= 28 - /** * Get a reference to the native ASurfaceTexture from the corresponding java object. * @@ -52,8 +50,6 @@ __BEGIN_DECLS */ ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture) __INTRODUCED_IN(28); -#endif - __END_DECLS #endif /* ANDROID_NATIVE_SURFACE_TEXTURE_JNI_H */ diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h index 6fd7d2c0ab..b0bbb954a9 100644 --- a/include/android/system_fonts.h +++ b/include/android/system_fonts.h @@ -87,8 +87,6 @@ __BEGIN_DECLS -#if __ANDROID_API__ >= 29 - /** * ASystemFontIterator provides access to the system font configuration. * @@ -128,8 +126,6 @@ void ASystemFontIterator_close(ASystemFontIterator* _Nullable iterator) __INTROD */ AFont* _Nullable ASystemFontIterator_next(ASystemFontIterator* _Nonnull iterator) __INTRODUCED_IN(29); -#endif // __ANDROID_API__ >= 29 - __END_DECLS #endif // ANDROID_SYSTEM_FONTS_H diff --git a/include/android/trace.h b/include/android/trace.h index dbad6f6f21..dcefffb20d 100644 --- a/include/android/trace.h +++ b/include/android/trace.h @@ -40,8 +40,6 @@ extern "C" { #endif -#if __ANDROID_API__ >= 23 - /** * Returns true if tracing is enabled. Use this to avoid expensive computation only necessary * when tracing is enabled. @@ -72,10 +70,6 @@ void ATrace_beginSection(const char* sectionName) __INTRODUCED_IN(23); */ void ATrace_endSection() __INTRODUCED_IN(23); -#endif /* __ANDROID_API__ >= 23 */ - -#if __ANDROID_API__ >= 29 - /** * Writes a trace message to indicate that a given section of code has * begun. Must be followed by a call to {@link ATrace_endAsyncSection} with the same @@ -112,8 +106,6 @@ void ATrace_endAsyncSection(const char* sectionName, int32_t cookie) __INTRODUCE */ void ATrace_setCounter(const char* counterName, int64_t counterValue) __INTRODUCED_IN(29); -#endif /* __ANDROID_API__ >= 29 */ - #ifdef __cplusplus } #endif diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h index 4fcca9e1d3..6ecb83ae0d 100644 --- a/libs/nativewindow/include/android/hardware_buffer.h +++ b/libs/nativewindow/include/android/hardware_buffer.h @@ -334,8 +334,6 @@ typedef struct AHardwareBuffer AHardwareBuffer; // clang-format on -#if __ANDROID_API__ >= 26 - /** * Allocates a buffer that matches the passed AHardwareBuffer_Desc. * @@ -478,10 +476,6 @@ int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer* _Nullable* _Nonnull outBuffer) __INTRODUCED_IN(26); -#endif // __ANDROID_API__ >= 26 - -#if __ANDROID_API__ >= 29 - /** * Lock a potentially multi-planar AHardwareBuffer for direct CPU access. * @@ -551,9 +545,6 @@ int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* _Nonnull buffer, uint64_t us int32_t* _Nonnull outBytesPerPixel, int32_t* _Nonnull outBytesPerStride) __INTRODUCED_IN(29); -#endif // __ANDROID_API__ >= 29 - -#if __ANDROID_API__ >= 31 /** * Get the system wide unique id for an AHardwareBuffer. @@ -566,8 +557,6 @@ int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* _Nonnull buffer, uint64_t us int AHardwareBuffer_getId(const AHardwareBuffer* _Nonnull buffer, uint64_t* _Nonnull outId) __INTRODUCED_IN(31); -#endif // __ANDROID_API__ >= 31 - __END_DECLS #endif // ANDROID_HARDWARE_BUFFER_H diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index deea59b9fb..285f2fb7fe 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -186,8 +186,6 @@ int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffe */ int32_t ANativeWindow_unlockAndPost(ANativeWindow* window); -#if __ANDROID_API__ >= 26 - /** * Set a transform that will be applied to future buffers posted to the window. * @@ -198,10 +196,6 @@ int32_t ANativeWindow_unlockAndPost(ANativeWindow* window); */ int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transform) __INTRODUCED_IN(26); -#endif // __ANDROID_API__ >= 26 - -#if __ANDROID_API__ >= 28 - /** * All buffers queued after this call will be associated with the dataSpace * parameter specified. @@ -230,10 +224,6 @@ int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpa */ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) __INTRODUCED_IN(28); -#endif // __ANDROID_API__ >= 28 - -#if __ANDROID_API__ >= 30 - /** Compatibility value for ANativeWindow_setFrameRate. */ enum ANativeWindow_FrameRateCompatibility { /** @@ -275,11 +265,7 @@ int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_ * * Available since API level 30. */ -void ANativeWindow_tryAllocateBuffers(ANativeWindow* window); - -#endif // __ANDROID_API__ >= 30 - -#if __ANDROID_API__ >= 31 +void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) __INTRODUCED_IN(30); /** * Sets the intended frame rate for this window. @@ -322,8 +308,6 @@ void ANativeWindow_tryAllocateBuffers(ANativeWindow* window); int32_t ANativeWindow_setFrameRateWithSeamlessness(ANativeWindow* window, float frameRate, int8_t compatibility, bool shouldBeSeamless) __INTRODUCED_IN(31); -#endif // __ANDROID_API__ >= 31 - #ifdef __cplusplus }; #endif -- cgit v1.2.3-59-g8ed1b From 51e6483b5cd569fdcc1b58b2881d2fa58d072cdf Mon Sep 17 00:00:00 2001 From: Galia Peycheva Date: Fri, 22 Jan 2021 13:50:16 +0000 Subject: Revert "Add permission check for blurs in SurfaceFlinger" Revert "Remove public usages of FLAG_BLUR_BEHIND" Revert "Add pid and uid to SF::setClientStateLocked" Revert "Add USE_BACKGROUND_BLUR to cts expected permissions" Revert submission 13350963-blur_system_api Reason for revert: This topic made blurs a system api. API council voted against that and we will instead aim to make it public for S. None of these changes are relevant in that case. Reverted Changes: I3683db296:Remove public usages of FLAG_BLUR_BEHIND I23b21b603:Add USE_BACKGROUND_BLUR to cts expected permission... Id21f03793:Add pid and uid to SF::setClientStateLocked If5d8344a5:Add permission for blur SystemApi I70d1e1715:Add permission check for blurs in SurfaceFlinger Icf98c3607:Make window background blurs SystemApi I0b881ec6e:Make BackgroundBlurDrawable a SystemApi Bug: 177523043 Test: m Change-Id: I4645b0483df69f4e5e970835fb3a232eb89c8f06 --- services/surfaceflinger/SurfaceFlinger.cpp | 19 ++++--------------- services/surfaceflinger/SurfaceFlinger.h | 4 ++-- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 91b111b16d..b2aa42ae9c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -275,7 +275,6 @@ const String16 sHardwareTest("android.permission.HARDWARE_TEST"); const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"); const String16 sRotateSurfaceFlinger("android.permission.ROTATE_SURFACE_FLINGER"); const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER"); -const String16 sUseBackgroundBlur("android.permission.USE_BACKGROUND_BLUR"); const String16 sDump("android.permission.DUMP"); const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled"; @@ -333,10 +332,6 @@ bool callingThreadHasRotateSurfaceFlingerAccess() { PermissionCache::checkPermission(sRotateSurfaceFlinger, pid, uid); } -bool originalCallerCanUseBlurs(int originPid, int originUid) { - return PermissionCache::checkPermission(sUseBackgroundBlur, originPid, originUid); -} - SurfaceFlingerBE::SurfaceFlingerBE() : mHwcServiceName(getHwcServiceName()) {} SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) @@ -3486,8 +3481,7 @@ void SurfaceFlinger::applyTransactionState( for (const ComposerState& state : states) { clientStateFlags |= setClientStateLocked(frameTimelineInfo, state, desiredPresentTime, isAutoTimestamp, - postTime, privileged, listenerCallbacksWithSurfaces, originPid, - originUid); + postTime, privileged, listenerCallbacksWithSurfaces); if ((flags & eAnimation) && state.state.surface) { if (const auto layer = fromHandleLocked(state.state.surface).promote(); layer) { mScheduler->recordLayerHistory(layer.get(), @@ -3667,8 +3661,7 @@ bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermis uint32_t SurfaceFlinger::setClientStateLocked( const FrameTimelineInfo& frameTimelineInfo, const ComposerState& composerState, int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, bool privileged, - std::unordered_set& listenerCallbacks, - int originPid, int originUid) { + std::unordered_set& listenerCallbacks) { const layer_state_t& s = composerState.state; for (auto& listener : s.listeners) { @@ -3814,14 +3807,10 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (layer->setCornerRadius(s.cornerRadius)) flags |= eTraversalNeeded; } - - if (what & layer_state_t::eBackgroundBlurRadiusChanged && !mDisableBlurs && mSupportsBlur && - originalCallerCanUseBlurs(originPid, originUid)) { + if (what & layer_state_t::eBackgroundBlurRadiusChanged && !mDisableBlurs && mSupportsBlur) { if (layer->setBackgroundBlurRadius(s.backgroundBlurRadius)) flags |= eTraversalNeeded; } - - if (what & layer_state_t::eBlurRegionsChanged && - originalCallerCanUseBlurs(originPid, originUid)) { + if (what & layer_state_t::eBlurRegionsChanged) { if (layer->setBlurRegions(s.blurRegions)) flags |= eTraversalNeeded; } if (what & layer_state_t::eLayerStackChanged) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f88b5fe266..729ef812d6 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -345,8 +345,8 @@ protected: virtual uint32_t setClientStateLocked( const FrameTimelineInfo& info, const ComposerState& composerState, int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, bool privileged, - std::unordered_set& listenerCallbacks, - int originPid, int originUid) REQUIRES(mStateLock); + std::unordered_set& listenerCallbacks) + REQUIRES(mStateLock); virtual void commitTransactionLocked(); // Used internally by computeLayerBounds() to gets the clip rectangle to use for the -- cgit v1.2.3-59-g8ed1b From 97cb066a0049c7ed8268ab436df0cc3cc843dabb Mon Sep 17 00:00:00 2001 From: Adithya Srinivasan Date: Thu, 14 Jan 2021 23:49:46 +0000 Subject: Fix Transaction tracking for FrameTimeline The current setup only supports one SurfaceFrame per DrawingState for Transactions. This becomes problematic if more than one Transaction is submitted for the same vsync, on the same layer. On top of this, the Blast transactions can have a buffer that could result in a buffer drop. This change adds the support to hold multiple SurfaceFrames in the Layer's State. It also adds a bufferSurfaceFrame that's intended only for Blast Transactions with a Buffer. All other Transactions are tracked in the bufferlessSurfaceFrames. Additionally, this change also adds a lastLatchTime. It is needed for classifying BufferStuffing properly. Bug: 176106798 Test: open any app from the launcher and at the same time check dumpsys Change-Id: Id3b8369ca206f8b89be3041e5fc018f1f1be1d23 --- services/surfaceflinger/BufferQueueLayer.cpp | 27 +- services/surfaceflinger/BufferQueueLayer.h | 5 - services/surfaceflinger/BufferStateLayer.cpp | 25 +- services/surfaceflinger/BufferStateLayer.h | 4 +- .../surfaceflinger/FrameTimeline/FrameTimeline.cpp | 4 + services/surfaceflinger/Layer.cpp | 139 +++++++- services/surfaceflinger/Layer.h | 46 ++- services/surfaceflinger/RefreshRateOverlay.cpp | 4 +- services/surfaceflinger/SurfaceFlinger.cpp | 9 +- services/surfaceflinger/tests/unittests/Android.bp | 1 + .../unittests/TransactionSurfaceFrameTest.cpp | 367 +++++++++++++++++++++ 11 files changed, 578 insertions(+), 53 deletions(-) create mode 100644 services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 52197873c5..3615a0209f 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -282,8 +282,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage); mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber); if (mQueueItems[0].surfaceFrame) { - mQueueItems[0].surfaceFrame->setPresentState(PresentState::Dropped); - mFlinger->mFrameTimeline->addSurfaceFrame(mQueueItems[0].surfaceFrame); + addSurfaceFrameDroppedForBuffer(mQueueItems[0].surfaceFrame); } mQueueItems.erase(mQueueItems.begin()); mQueuedFrames--; @@ -298,8 +297,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t Mutex::Autolock lock(mQueueItemLock); for (auto& [item, surfaceFrame] : mQueueItems) { if (surfaceFrame) { - surfaceFrame->setPresentState(PresentState::Dropped); - mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame); + addSurfaceFrameDroppedForBuffer(surfaceFrame); } } mQueueItems.clear(); @@ -329,8 +327,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage); mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber); if (mQueueItems[0].surfaceFrame) { - mQueueItems[0].surfaceFrame->setPresentState(PresentState::Dropped); - mFlinger->mFrameTimeline->addSurfaceFrame(mQueueItems[0].surfaceFrame); + addSurfaceFrameDroppedForBuffer(mQueueItems[0].surfaceFrame); } mQueueItems.erase(mQueueItems.begin()); mQueuedFrames--; @@ -342,11 +339,9 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t FrameTracer::FrameEvent::LATCH); if (mQueueItems[0].surfaceFrame) { - mQueueItems[0].surfaceFrame->setAcquireFenceTime( - mQueueItems[0].item.mFenceTime->getSignalTime()); - mQueueItems[0].surfaceFrame->setPresentState(PresentState::Presented, mLastLatchTime); - mFlinger->mFrameTimeline->addSurfaceFrame(mQueueItems[0].surfaceFrame); - mLastLatchTime = latchTime; + addSurfaceFramePresentedForBuffer(mQueueItems[0].surfaceFrame, + mQueueItems[0].item.mFenceTime->getSignalTime(), + latchTime); } mQueueItems.erase(mQueueItems.begin()); } @@ -444,10 +439,7 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { } } - auto surfaceFrame = - mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineInfo, mOwnerPid, - mOwnerUid, mName, mName); - surfaceFrame->setActualQueueTime(systemTime()); + auto surfaceFrame = createSurfaceFrameForBuffer(mFrameTimelineInfo, systemTime(), mName); mQueueItems.push_back({item, surfaceFrame}); mQueuedFrames++; @@ -483,10 +475,7 @@ void BufferQueueLayer::onFrameReplaced(const BufferItem& item) { return; } - auto surfaceFrame = - mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineInfo, mOwnerPid, - mOwnerUid, mName, mName); - surfaceFrame->setActualQueueTime(systemTime()); + auto surfaceFrame = createSurfaceFrameForBuffer(mFrameTimelineInfo, systemTime(), mName); mQueueItems[mQueueItems.size() - 1].item = item; mQueueItems[mQueueItems.size() - 1].surfaceFrame = std::move(surfaceFrame); diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index 41ff01262e..0ea02e19a7 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -149,11 +149,6 @@ private: // a buffer to correlate the buffer with the vsync id. Can only be accessed // with the SF state lock held. FrameTimelineInfo mFrameTimelineInfo; - - // Keeps track of the time SF latched the last buffer from this layer. - // Used in buffer stuffing analysis in FrameTimeline. - // TODO(b/176106798): Find a way to do this for BLASTBufferQueue as well. - nsecs_t mLastLatchTime = 0; }; } // namespace android diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 3dc62e3091..e470eb940c 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -28,6 +28,7 @@ #include +#include #include #include #include @@ -38,6 +39,7 @@ namespace android { +using PresentState = frametimeline::SurfaceFrame::PresentState; // clang-format off const std::array BufferStateLayer::IDENTITY_MATRIX{ 1, 0, 0, 0, @@ -335,7 +337,8 @@ bool BufferStateLayer::addFrameEvent(const sp& acquireFence, nsecs_t post bool BufferStateLayer::setBuffer(const sp& buffer, const sp& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber, - std::optional /* dequeueTime */) { + std::optional /* dequeueTime */, + const FrameTimelineInfo& info) { ATRACE_CALL(); if (mCurrentState.buffer) { @@ -345,6 +348,10 @@ bool BufferStateLayer::setBuffer(const sp& buffer, const sp& buffer, const sp(mDrawingState.acquireFence)); mFlinger->mTimeStats->setLatchTime(layerId, mDrawingState.frameNumber, latchTime); + auto& bufferSurfaceFrame = mDrawingState.bufferSurfaceFrameTX; + if (bufferSurfaceFrame != nullptr && + bufferSurfaceFrame->getPresentState() != PresentState::Presented) { + // Update only if the bufferSurfaceFrame wasn't already presented. A Presented + // bufferSurfaceFrame could be seen here if a pending state was applied successfully and we + // are processing the next state. + addSurfaceFramePresentedForBuffer(bufferSurfaceFrame, + mDrawingState.acquireFence->getSignalTime(), latchTime); + bufferSurfaceFrame.reset(); + } + mCurrentStateModified = false; return NO_ERROR; diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index b93d567e20..ea832a2078 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -72,7 +72,7 @@ public: bool setBuffer(const sp& buffer, const sp& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber, - std::optional dequeueTime) override; + std::optional dequeueTime, const FrameTimelineInfo& info) override; bool setAcquireFence(const sp& fence) override; bool setDataspace(ui::Dataspace dataspace) override; bool setHdrMetadata(const HdrMetadata& hdrMetadata) override; @@ -124,6 +124,8 @@ protected: private: friend class SlotGenerationTest; + friend class TransactionSurfaceFrameTest; + inline void tracePendingBufferCount(); bool updateFrameEventHistory(const sp& acquireFence, nsecs_t postedTime, diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 3743716876..3f833f4890 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -312,6 +312,10 @@ void SurfaceFrame::setAcquireFenceTime(nsecs_t acquireFenceTime) { void SurfaceFrame::setPresentState(PresentState presentState, nsecs_t lastLatchTime) { std::scoped_lock lock(mMutex); + LOG_ALWAYS_FATAL_IF(mPresentState != PresentState::Unknown, + "setPresentState called on a SurfaceFrame from Layer - %s, that has a " + "PresentState - %s set already.", + mDebugName.c_str(), toString(mPresentState).c_str()); mPresentState = presentState; mLastLatchTime = lastLatchTime; } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 08a5f0fdb8..df14003c75 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -841,13 +841,35 @@ void Layer::pushPendingState() { setTransactionFlags(eTransactionNeeded); mFlinger->setTransactionFlags(eTraversalNeeded); } + if (mCurrentState.bufferlessSurfaceFramesTX.size() >= State::kStateSurfaceFramesThreshold) { + // Ideally, the currentState would only contain one SurfaceFrame per transaction (assuming + // each Tx uses a different token). We don't expect the current state to hold a huge amount + // of SurfaceFrames. However, in the event it happens, this debug statement will leave a + // trail that can help in debugging. + ALOGW("Bufferless SurfaceFrames size on current state of layer %s is %" PRIu32 "", + mName.c_str(), static_cast(mCurrentState.bufferlessSurfaceFramesTX.size())); + } mPendingStates.push_back(mCurrentState); + // Since the current state along with the SurfaceFrames has been pushed into the pendingState, + // we no longer need to retain them. If multiple states are pushed and applied together, we have + // a merging logic to address the SurfaceFrames at mergeSurfaceFrames(). + mCurrentState.bufferlessSurfaceFramesTX.clear(); ATRACE_INT(mTransactionName.c_str(), mPendingStates.size()); } +void Layer::mergeSurfaceFrames(State& source, State& target) { + // No need to merge BufferSurfaceFrame as the target's surfaceFrame, if it exists, will be used + // directly. Dropping of source's SurfaceFrame is taken care of at setBuffer(). + target.bufferlessSurfaceFramesTX.merge(source.bufferlessSurfaceFramesTX); + source.bufferlessSurfaceFramesTX.clear(); +} + void Layer::popPendingState(State* stateToCommit) { ATRACE_CALL(); + if (stateToCommit != nullptr) { + mergeSurfaceFrames(*stateToCommit, mPendingStates[0]); + } *stateToCommit = mPendingStates[0]; mPendingStates.pop_front(); ATRACE_INT(mTransactionName.c_str(), mPendingStates.size()); @@ -906,20 +928,6 @@ bool Layer::applyPendingStates(State* stateToCommit) { mFlinger->setTraversalNeeded(); } - if (stateUpdateAvailable) { - mSurfaceFrame = - mFlinger->mFrameTimeline - ->createSurfaceFrameForToken(stateToCommit->frameTimelineInfo, mOwnerPid, - mOwnerUid, mName, mTransactionName); - mSurfaceFrame->setActualQueueTime(stateToCommit->postTime); - // For transactions we set the acquire fence time to the post time as we - // don't have a buffer. For BufferStateLayer it is overridden in - // BufferStateLayer::applyPendingStates - mSurfaceFrame->setAcquireFenceTime(stateToCommit->postTime); - - onSurfaceFrameCreated(mSurfaceFrame); - } - mCurrentState.modified = false; return stateUpdateAvailable; } @@ -1048,10 +1056,22 @@ uint32_t Layer::doTransaction(uint32_t flags) { return flags; } -void Layer::commitTransaction(const State& stateToCommit) { +void Layer::commitTransaction(State& stateToCommit) { mDrawingState = stateToCommit; - mSurfaceFrame->setPresentState(PresentState::Presented); - mFlinger->mFrameTimeline->addSurfaceFrame(mSurfaceFrame); + + // Set the present state for all bufferlessSurfaceFramesTX to Presented. The + // bufferSurfaceFrameTX will be presented in latchBuffer. + for (auto& [token, surfaceFrame] : mDrawingState.bufferlessSurfaceFramesTX) { + if (surfaceFrame->getPresentState() != PresentState::Presented) { + // With applyPendingStates, we could end up having presented surfaceframes from previous + // states + surfaceFrame->setPresentState(PresentState::Presented); + mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame); + } + } + // Clear the surfaceFrames from the old state now that it has been copied into DrawingState. + stateToCommit.bufferSurfaceFrameTX.reset(); + stateToCommit.bufferlessSurfaceFramesTX.clear(); } uint32_t Layer::getTransactionFlags(uint32_t flags) { @@ -1474,11 +1494,94 @@ bool Layer::setFrameRate(FrameRate frameRate) { return true; } -void Layer::setFrameTimelineInfoForTransaction(const FrameTimelineInfo& info, nsecs_t postTime) { +void Layer::setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info, + nsecs_t postTime) { + mCurrentState.postTime = postTime; + + // Check if one of the bufferlessSurfaceFramesTX contains the same vsyncId. This can happen if + // there are two transactions with the same token, the first one without a buffer and the + // second one with a buffer. We promote the bufferlessSurfaceFrame to a bufferSurfaceFrameTX + // in that case. + auto it = mCurrentState.bufferlessSurfaceFramesTX.find(info.vsyncId); + if (it != mCurrentState.bufferlessSurfaceFramesTX.end()) { + // Promote the bufferlessSurfaceFrame to a bufferSurfaceFrameTX + mCurrentState.bufferSurfaceFrameTX = it->second; + mCurrentState.bufferlessSurfaceFramesTX.erase(it); + mCurrentState.bufferSurfaceFrameTX->setActualQueueTime(postTime); + } else { + mCurrentState.bufferSurfaceFrameTX = + createSurfaceFrameForBuffer(info, postTime, mTransactionName); + } +} + +void Layer::setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInfo& info, + nsecs_t postTime) { mCurrentState.frameTimelineInfo = info; mCurrentState.postTime = postTime; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); + + if (const auto& bufferSurfaceFrameTX = mCurrentState.bufferSurfaceFrameTX; + bufferSurfaceFrameTX != nullptr) { + if (bufferSurfaceFrameTX->getToken() == info.vsyncId) { + // BufferSurfaceFrame takes precedence over BufferlessSurfaceFrame. If the same token is + // being used for BufferSurfaceFrame, don't create a new one. + return; + } + } + // For Transactions without a buffer, we create only one SurfaceFrame per vsyncId. If multiple + // transactions use the same vsyncId, we just treat them as one SurfaceFrame (unless they are + // targeting different vsyncs). + auto it = mCurrentState.bufferlessSurfaceFramesTX.find(info.vsyncId); + if (it == mCurrentState.bufferlessSurfaceFramesTX.end()) { + auto surfaceFrame = createSurfaceFrameForTransaction(info, postTime); + mCurrentState.bufferlessSurfaceFramesTX[info.vsyncId] = surfaceFrame; + } else { + if (it->second->getPresentState() == PresentState::Presented) { + // If the SurfaceFrame was already presented, its safe to overwrite it since it must + // have been from previous vsync. + it->second = createSurfaceFrameForTransaction(info, postTime); + } + } +} + +void Layer::addSurfaceFrameDroppedForBuffer( + std::shared_ptr& surfaceFrame) { + surfaceFrame->setPresentState(PresentState::Dropped); + mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame); +} + +void Layer::addSurfaceFramePresentedForBuffer( + std::shared_ptr& surfaceFrame, nsecs_t acquireFenceTime, + nsecs_t currentLatchTime) { + surfaceFrame->setAcquireFenceTime(acquireFenceTime); + surfaceFrame->setPresentState(PresentState::Presented, mLastLatchTime); + mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame); + mLastLatchTime = currentLatchTime; +} + +std::shared_ptr Layer::createSurfaceFrameForTransaction( + const FrameTimelineInfo& info, nsecs_t postTime) { + auto surfaceFrame = + mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid, mName, + mTransactionName); + // For Transactions, the post time is considered to be both queue and acquire fence time. + surfaceFrame->setActualQueueTime(postTime); + surfaceFrame->setAcquireFenceTime(postTime); + onSurfaceFrameCreated(surfaceFrame); + return surfaceFrame; +} + +std::shared_ptr Layer::createSurfaceFrameForBuffer( + const FrameTimelineInfo& info, nsecs_t queueTime, std::string debugName) { + auto surfaceFrame = + mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid, mName, + debugName); + // For buffers, acquire fence time will set during latch. + surfaceFrame->setActualQueueTime(queueTime); + // TODO(b/178542907): Implement onSurfaceFrameCreated for BQLayer as well. + onSurfaceFrameCreated(surfaceFrame); + return surfaceFrame; } Layer::FrameRate Layer::getFrameRateForLayerTree() const { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 4b40c8ed83..89f26966fb 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -309,6 +309,20 @@ public: // When the transaction was posted nsecs_t postTime; + + // SurfaceFrame that tracks the timeline of Transactions that contain a Buffer. Only one + // such SurfaceFrame exists because only one buffer can be presented on the layer per vsync. + // If multiple buffers are queued, the prior ones will be dropped, along with the + // SurfaceFrame that's tracking them. + std::shared_ptr bufferSurfaceFrameTX; + // A map of token(frametimelineVsyncId) to the SurfaceFrame that's tracking a transaction + // that contains the token. Only one SurfaceFrame exisits for transactions that share the + // same token, unless they are presented in different vsyncs. + std::unordered_map> + bufferlessSurfaceFramesTX; + // An arbitrary threshold for the number of BufferlessSurfaceFrames in the state. Used to + // trigger a warning if the number of SurfaceFrames crosses the threshold. + static constexpr uint32_t kStateSurfaceFramesThreshold = 25; }; /* @@ -447,7 +461,8 @@ public: virtual bool setBuffer(const sp& /*buffer*/, const sp& /*acquireFence*/, nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/, const client_cache_t& /*clientCacheId*/, - uint64_t /* frameNumber */, std::optional /* dequeueTime */) { + uint64_t /* frameNumber */, std::optional /* dequeueTime */, + const FrameTimelineInfo& /*info*/) { return false; }; virtual bool setAcquireFence(const sp& /*fence*/) { return false; }; @@ -611,6 +626,12 @@ public: virtual void pushPendingState(); + /* + * Merges the BufferlessSurfaceFrames from source with the target. If the same token exists in + * both source and target, target's SurfaceFrame will be retained. + */ + void mergeSurfaceFrames(State& source, State& target); + /** * Returns active buffer size in the correct orientation. Buffer size is determined by undoing * any buffer transformations. If the layer has no buffer then return INVALID_RECT. @@ -866,8 +887,20 @@ public: bool setFrameRate(FrameRate); virtual void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {} - void setFrameTimelineInfoForTransaction(const FrameTimelineInfo& frameTimelineInfo, - nsecs_t postTime); + void setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info, nsecs_t postTime); + void setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInfo& info, + nsecs_t postTime); + + void addSurfaceFrameDroppedForBuffer( + std::shared_ptr& surfaceFrame); + void addSurfaceFramePresentedForBuffer( + std::shared_ptr& surfaceFrame, nsecs_t acquireFenceTime, + nsecs_t currentLatchTime); + + std::shared_ptr createSurfaceFrameForTransaction( + const FrameTimelineInfo& info, nsecs_t postTime); + std::shared_ptr createSurfaceFrameForBuffer( + const FrameTimelineInfo& info, nsecs_t queueTime, std::string debugName); // Creates a new handle each time, so we only expect // this to be called once. @@ -972,6 +1005,7 @@ protected: friend class TestableSurfaceFlinger; friend class RefreshRateSelectionTest; friend class SetFrameRateTest; + friend class TransactionSurfaceFrameTest; virtual void setInitialValuesForClone(const sp& clonedFrom); virtual std::optional prepareClientComposition( @@ -980,7 +1014,7 @@ protected: const LayerFE::LayerSettings&, const Rect& layerStackRect, ui::Dataspace outputDataspace); virtual void preparePerFrameCompositionState(); - virtual void commitTransaction(const State& stateToCommit); + virtual void commitTransaction(State& stateToCommit); virtual bool applyPendingStates(State* stateToCommit); virtual uint32_t doTransactionResize(uint32_t flags, Layer::State* stateToCommit); virtual void onSurfaceFrameCreated(const std::shared_ptr&) {} @@ -1116,6 +1150,10 @@ protected: // If created from a system process, the value can be passed in. pid_t mOwnerPid; + // Keeps track of the time SF latched the last buffer from this layer. + // Used in buffer stuffing analysis in FrameTimeline. + nsecs_t mLastLatchTime = 0; + private: virtual void setTransformHint(ui::Transform::RotationFlags) {} diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 9230e72f45..49ffc81359 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -238,7 +238,7 @@ void RefreshRateOverlay::changeRefreshRate(const Fps& fps) { auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame]; mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {}, mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */), - std::nullopt /* dequeueTime */); + std::nullopt /* dequeueTime */, FrameTimelineInfo{}); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } @@ -251,7 +251,7 @@ void RefreshRateOverlay::onInvalidate() { auto buffer = buffers[mFrame]; mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {}, mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */), - std::nullopt /* dequeueTime */); + std::nullopt /* dequeueTime */, FrameTimelineInfo{}); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e9b587510a..4712328f18 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3931,10 +3931,11 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTraversalNeeded; } } + FrameTimelineInfo info; if (what & layer_state_t::eFrameTimelineInfoChanged) { - layer->setFrameTimelineInfoForTransaction(s.frameTimelineInfo, postTime); + info = s.frameTimelineInfo; } else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { - layer->setFrameTimelineInfoForTransaction(frameTimelineInfo, postTime); + info = frameTimelineInfo; } if (what & layer_state_t::eFixedTransformHintChanged) { if (layer->setFixedTransformHint(s.fixedTransformHint)) { @@ -3993,9 +3994,11 @@ uint32_t SurfaceFlinger::setClientStateLocked( : layer->getHeadFrameNumber(-1 /* expectedPresentTime */) + 1; if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, isAutoTimestamp, - s.cachedBuffer, frameNumber, dequeueBufferTimestamp)) { + s.cachedBuffer, frameNumber, dequeueBufferTimestamp, info)) { flags |= eTraversalNeeded; } + } else if (info.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { + layer->setFrameTimelineVsyncForBufferlessTransaction(info, postTime); } if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded; diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 13b26fcc97..7ae09fa0b4 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -73,6 +73,7 @@ cc_test { "FrameTracerTest.cpp", "TimerTest.cpp", "TransactionApplicationTest.cpp", + "TransactionSurfaceFrameTest.cpp", "StrongTypingTest.cpp", "VSyncDispatchTimerQueueTest.cpp", "VSyncDispatchRealtimeTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp new file mode 100644 index 0000000000..aa6798d84c --- /dev/null +++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp @@ -0,0 +1,367 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef LOG_TAG +#define LOG_TAG "LibSurfaceFlingerUnittests" + +#include +#include +#include +#include +#include + +#include "TestableSurfaceFlinger.h" +#include "mock/DisplayHardware/MockComposer.h" +#include "mock/MockEventThread.h" +#include "mock/MockVsyncController.h" + +namespace android { + +using testing::_; +using testing::Mock; +using testing::Return; +using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; +using PresentState = frametimeline::SurfaceFrame::PresentState; + +class TransactionSurfaceFrameTest : public testing::Test { +public: + TransactionSurfaceFrameTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); + setupScheduler(); + setupComposer(0); + } + + ~TransactionSurfaceFrameTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); + } + + sp createBufferStateLayer() { + sp client; + LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 100, 100, 0, + LayerMetadata()); + return new BufferStateLayer(args); + } + + void commitTransaction(Layer* layer) { + layer->pushPendingState(); + // After pushing the state, the currentState should not store any BufferlessSurfaceFrames + EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); + auto c = layer->getCurrentState(); + if (layer->applyPendingStates(&c)) { + layer->commitTransaction(c); + } + } + + void setupScheduler() { + auto eventThread = std::make_unique(); + auto sfEventThread = std::make_unique(); + + EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*eventThread, createEventConnection(_, _)) + .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0, + ResyncCallback()))); + + EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) + .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0, + ResyncCallback()))); + + auto vsyncController = std::make_unique(); + auto vsyncTracker = std::make_unique(); + + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + EXPECT_CALL(*vsyncTracker, currentPeriod()) + .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), + std::move(eventThread), std::move(sfEventThread)); + } + + void setupComposer(uint32_t virtualDisplayCount) { + mComposer = new Hwc2::mock::Composer(); + EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount)); + mFlinger.setupComposer(std::unique_ptr(mComposer)); + + Mock::VerifyAndClear(mComposer); + } + + TestableSurfaceFlinger mFlinger; + Hwc2::mock::Composer* mComposer = nullptr; + FenceToFenceTimeMap fenceFactory; + client_cache_t mClientCache; + + void PresentedSurfaceFrameForBufferlessTransaction() { + sp layer = createBufferStateLayer(); + layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, + 10); + EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); + ASSERT_TRUE(layer->mCurrentState.bufferSurfaceFrameTX == nullptr); + const auto surfaceFrame = layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1); + commitTransaction(layer.get()); + EXPECT_EQ(1, surfaceFrame->getToken()); + EXPECT_EQ(PresentState::Presented, surfaceFrame->getPresentState()); + } + + void PresentedSurfaceFrameForBufferTransaction() { + sp layer = createBufferStateLayer(); + sp fence(new Fence()); + auto acquireFence = fenceFactory.createFenceTimeForTest(fence); + sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, + {/*vsyncId*/ 1, /*inputEventId*/ 0}); + acquireFence->signalForTest(12); + + commitTransaction(layer.get()); + EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); + ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); + const auto& surfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX; + // Buffers are presented only at latch time. + EXPECT_EQ(PresentState::Unknown, surfaceFrame->getPresentState()); + + bool computeVisisbleRegions; + layer->updateTexImage(computeVisisbleRegions, 15, 0); + + EXPECT_EQ(1, surfaceFrame->getToken()); + EXPECT_EQ(PresentState::Presented, surfaceFrame->getPresentState()); + } + + void DroppedSurfaceFrameForBufferTransaction() { + sp layer = createBufferStateLayer(); + + sp fence1(new Fence()); + auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); + sp buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, + {/*vsyncId*/ 1, /*inputEventId*/ 0}); + EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); + ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); + const auto droppedSurfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX; + + sp fence2(new Fence()); + auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); + sp buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, + {/*vsyncId*/ 1, /*inputEventId*/ 0}); + acquireFence2->signalForTest(12); + + EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); + ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); + const auto& presentedSurfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX; + + commitTransaction(layer.get()); + bool computeVisisbleRegions; + layer->updateTexImage(computeVisisbleRegions, 15, 0); + + EXPECT_EQ(1, droppedSurfaceFrame->getToken()); + EXPECT_EQ(PresentState::Dropped, droppedSurfaceFrame->getPresentState()); + + EXPECT_EQ(1, presentedSurfaceFrame->getToken()); + EXPECT_EQ(PresentState::Presented, presentedSurfaceFrame->getPresentState()); + } + + void BufferlessSurfaceFramePromotedToBufferSurfaceFrame() { + sp layer = createBufferStateLayer(); + + layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, + 10); + + EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); + ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); + + sp fence(new Fence()); + auto acquireFence = fenceFactory.createFenceTimeForTest(fence); + sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + + layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, + {/*vsyncId*/ 1, /*inputEventId*/ 0}); + acquireFence->signalForTest(12); + + EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); + ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); + const auto& surfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX; + + commitTransaction(layer.get()); + EXPECT_EQ(1, surfaceFrame->getToken()); + // Buffers are presented only at latch time. + EXPECT_EQ(PresentState::Unknown, surfaceFrame->getPresentState()); + + bool computeVisisbleRegions; + layer->updateTexImage(computeVisisbleRegions, 15, 0); + + EXPECT_EQ(PresentState::Presented, surfaceFrame->getPresentState()); + } + + void BufferlessSurfaceFrameNotCreatedIfBufferSufaceFrameExists() { + sp layer = createBufferStateLayer(); + sp fence(new Fence()); + auto acquireFence = fenceFactory.createFenceTimeForTest(fence); + sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + + layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, + {/*vsyncId*/ 1, /*inputEventId*/ 0}); + EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); + ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); + + layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, + 10); + EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); + ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); + } + + void MultipleSurfaceFramesPresentedTogether() { + sp layer = createBufferStateLayer(); + layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, + 10); + EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); + ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); + const auto bufferlessSurfaceFrame1 = + layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1); + + layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 4, /*inputEventId*/ 0}, + 10); + EXPECT_EQ(2u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); + ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); + const auto bufferlessSurfaceFrame2 = layer->mCurrentState.bufferlessSurfaceFramesTX[4]; + + sp fence(new Fence()); + auto acquireFence = fenceFactory.createFenceTimeForTest(fence); + sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + + layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, + {/*vsyncId*/ 3, /*inputEventId*/ 0}); + EXPECT_EQ(2u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); + ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); + const auto& bufferSurfaceFrameTX = layer->mCurrentState.bufferSurfaceFrameTX; + + acquireFence->signalForTest(12); + + commitTransaction(layer.get()); + + EXPECT_EQ(1, bufferlessSurfaceFrame1->getToken()); + EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame1->getPresentState()); + + EXPECT_EQ(4, bufferlessSurfaceFrame2->getToken()); + EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame2->getPresentState()); + + EXPECT_EQ(3, bufferSurfaceFrameTX->getToken()); + // Buffers are presented only at latch time. + EXPECT_EQ(PresentState::Unknown, bufferSurfaceFrameTX->getPresentState()); + + bool computeVisisbleRegions; + layer->updateTexImage(computeVisisbleRegions, 15, 0); + + EXPECT_EQ(PresentState::Presented, bufferSurfaceFrameTX->getPresentState()); + } + + void MergePendingStates_BufferlessSurfaceFramesWithoutOverlappingToken() { + sp layer = createBufferStateLayer(); + layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, + 10); + EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); + ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); + const auto bufferlessSurfaceFrame1 = + layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1); + + layer->pushPendingState(); + EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); + + layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 2, /*inputEventId*/ 0}, + 12); + EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); + ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); + const auto bufferlessSurfaceFrame2 = + layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 2); + + commitTransaction(layer.get()); + + EXPECT_EQ(1, bufferlessSurfaceFrame1->getToken()); + EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame1->getPresentState()); + EXPECT_EQ(10, bufferlessSurfaceFrame1->getActuals().endTime); + + EXPECT_EQ(2, bufferlessSurfaceFrame2->getToken()); + EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame2->getPresentState()); + EXPECT_EQ(12, bufferlessSurfaceFrame2->getActuals().endTime); + } + + void MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken() { + sp layer = createBufferStateLayer(); + layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, + 10); + EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); + ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); + const auto bufferlessSurfaceFrame1 = + layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1); + + layer->pushPendingState(); + EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); + + layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, + 12); + EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); + ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); + const auto bufferlessSurfaceFrame2 = + layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1); + + commitTransaction(layer.get()); + + EXPECT_EQ(1, bufferlessSurfaceFrame1->getToken()); + EXPECT_EQ(PresentState::Unknown, bufferlessSurfaceFrame1->getPresentState()); + + EXPECT_EQ(1, bufferlessSurfaceFrame2->getToken()); + EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame2->getPresentState()); + EXPECT_EQ(12, bufferlessSurfaceFrame2->getActuals().endTime); + } +}; + +TEST_F(TransactionSurfaceFrameTest, PresentedBufferlessSurfaceFrame) { + PresentedSurfaceFrameForBufferlessTransaction(); +} + +TEST_F(TransactionSurfaceFrameTest, PresentedBufferSurfaceFrame) { + PresentedSurfaceFrameForBufferTransaction(); +} + +TEST_F(TransactionSurfaceFrameTest, DroppedBufferSurfaceFrame) { + DroppedSurfaceFrameForBufferTransaction(); +} + +TEST_F(TransactionSurfaceFrameTest, BufferlessSurfaceFramePromotedToBufferSurfaceFrame) { + BufferlessSurfaceFramePromotedToBufferSurfaceFrame(); +} + +TEST_F(TransactionSurfaceFrameTest, BufferlessSurfaceFrameNotCreatedIfBufferSufaceFrameExists) { + BufferlessSurfaceFrameNotCreatedIfBufferSufaceFrameExists(); +} + +TEST_F(TransactionSurfaceFrameTest, MultipleSurfaceFramesPresentedTogether) { + MultipleSurfaceFramesPresentedTogether(); +} + +TEST_F(TransactionSurfaceFrameTest, + MergePendingStates_BufferlessSurfaceFramesWithoutOverlappingToken) { + MergePendingStates_BufferlessSurfaceFramesWithoutOverlappingToken(); +} + +TEST_F(TransactionSurfaceFrameTest, + MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken) { + MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken(); +} + +} // namespace android \ No newline at end of file -- cgit v1.2.3-59-g8ed1b From 83a29ce9fe8308d61856fd798ad7e960517d1690 Mon Sep 17 00:00:00 2001 From: Brian Osman Date: Wed, 17 Feb 2021 16:51:17 +0000 Subject: Add missing include for SkRRect Change-Id: Id71c79655c86f4a83c3d411eb56db48264b268b8 --- libs/renderengine/skia/filters/BlurFilter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp index 9d20e327a8..5960e48f7b 100644 --- a/libs/renderengine/skia/filters/BlurFilter.cpp +++ b/libs/renderengine/skia/filters/BlurFilter.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3-59-g8ed1b From 798c190b715c39897d99cb33d920be28367d5917 Mon Sep 17 00:00:00 2001 From: Ryan Savitski Date: Mon, 15 Feb 2021 20:23:20 +0000 Subject: atrace.rc: allow select tracepoints on release builds See the bug and the associated SELinux policy change (aosp/1594256) for context. Sending to internal master as it's ahead of aosp. Bug: 179788446 Change-Id: I24d94e63b06d0ec2b1b091fd635b9f059df7f75d --- cmds/atrace/atrace.rc | 16 ++++++++++++++++ cmds/atrace/atrace_userdebug.rc | 5 ----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index c7c3a34521..006e5329cd 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -37,12 +37,18 @@ on late-init chmod 0666 /sys/kernel/tracing/events/sched/sched_process_exit/enable chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_waking/enable chmod 0666 /sys/kernel/tracing/events/sched/sched_waking/enable + chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_wakeup_new/enable + chmod 0666 /sys/kernel/tracing/events/sched/sched_wakeup_new/enable chmod 0666 /sys/kernel/debug/tracing/events/cgroup/enable chmod 0666 /sys/kernel/tracing/events/cgroup/enable chmod 0666 /sys/kernel/debug/tracing/events/power/cpu_frequency/enable chmod 0666 /sys/kernel/tracing/events/power/cpu_frequency/enable chmod 0666 /sys/kernel/debug/tracing/events/power/cpu_idle/enable chmod 0666 /sys/kernel/tracing/events/power/cpu_idle/enable + chmod 0666 /sys/kernel/debug/tracing/events/power/clock_enable/enable + chmod 0666 /sys/kernel/tracing/events/power/clock_enable/enable + chmod 0666 /sys/kernel/debug/tracing/events/power/clock_disable/enable + chmod 0666 /sys/kernel/tracing/events/power/clock_disable/enable chmod 0666 /sys/kernel/debug/tracing/events/power/clock_set_rate/enable chmod 0666 /sys/kernel/tracing/events/power/clock_set_rate/enable chmod 0666 /sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable @@ -79,6 +85,8 @@ on late-init chmod 0666 /sys/kernel/tracing/events/binder/binder_locked/enable chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_unlock/enable chmod 0666 /sys/kernel/tracing/events/binder/binder_unlock/enable + chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_set_priority/enable + chmod 0666 /sys/kernel/tracing/events/binder/binder_set_priority/enable chmod 0666 /sys/kernel/debug/tracing/events/i2c/enable chmod 0666 /sys/kernel/tracing/events/i2c/enable chmod 0666 /sys/kernel/debug/tracing/events/i2c/i2c_read/enable @@ -125,6 +133,8 @@ on late-init chmod 0666 /sys/kernel/tracing/events/lowmemorykiller/lowmemory_kill/enable chmod 0666 /sys/kernel/debug/tracing/events/oom/oom_score_adj_update/enable chmod 0666 /sys/kernel/tracing/events/oom/oom_score_adj_update/enable + chmod 0666 /sys/kernel/debug/tracing/events/oom/mark_victim/enable + chmod 0666 /sys/kernel/tracing/events/oom/mark_victim/enable chmod 0666 /sys/kernel/debug/tracing/events/task/task_rename/enable chmod 0666 /sys/kernel/tracing/events/task/task_rename/enable chmod 0666 /sys/kernel/debug/tracing/events/task/task_newtask/enable @@ -159,6 +169,12 @@ on late-init chmod 0666 /sys/kernel/tracing/events/ipi/ipi_exit/enable chmod 0666 /sys/kernel/debug/tracing/events/ipi/ipi_raise/enable chmod 0666 /sys/kernel/tracing/events/ipi/ipi_raise/enable + chmod 0666 /sys/kernel/debug/tracing/events/clk/clk_enable/enable + chmod 0666 /sys/kernel/tracing/events/clk/clk_disable/enable + chmod 0666 /sys/kernel/debug/tracing/events/clk/clk_disable/enable + chmod 0666 /sys/kernel/tracing/events/clk/clk_enable/enable + chmod 0666 /sys/kernel/debug/tracing/events/clk/clk_set_rate/enable + chmod 0666 /sys/kernel/tracing/events/clk/clk_set_rate/enable # disk chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable diff --git a/cmds/atrace/atrace_userdebug.rc b/cmds/atrace/atrace_userdebug.rc index 6c86c21387..9186514d0a 100644 --- a/cmds/atrace/atrace_userdebug.rc +++ b/cmds/atrace/atrace_userdebug.rc @@ -18,8 +18,3 @@ on post-fs chmod 0666 /sys/kernel/tracing/events/filemap/enable chmod 0666 /sys/kernel/debug/tracing/events/filemap/enable - # irq - chmod 0666 /sys/kernel/tracing/events/irq/enable - chmod 0666 /sys/kernel/debug/tracing/events/irq/enable - chmod 0666 /sys/kernel/tracing/events/ipi/enable - chmod 0666 /sys/kernel/debug/tracing/events/ipi/enable -- cgit v1.2.3-59-g8ed1b From a0f961f92b98f8ddea7e970929ba9ce4a699f824 Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Tue, 23 Feb 2021 21:33:34 -0800 Subject: [LSC] Add LOCAL_LICENSE_KINDS to frameworks/native Added SPDX-license-identifier-Apache-2.0 to: cmds/atrace/Android.bp cmds/bugreport/Android.bp cmds/bugreportz/Android.bp cmds/cmd/Android.bp cmds/dumpstate/Android.bp cmds/dumpsys/Android.bp cmds/dumpsys/tests/Android.bp cmds/flatland/Android.mk cmds/idlcli/Android.bp cmds/installd/Android.bp cmds/installd/tests/Android.bp cmds/ip-up-vpn/Android.mk cmds/lshal/Android.bp cmds/lshal/libprocpartition/Android.bp cmds/rawbu/Android.bp cmds/rss_hwm_reset/Android.bp cmds/service/Android.bp cmds/servicemanager/Android.bp cmds/surfacereplayer/Android.bp cmds/surfacereplayer/proto/Android.bp cmds/surfacereplayer/replayer/Android.bp data/etc/Android.bp libs/adbd_auth/Android.bp libs/android_runtime_lazy/Android.bp libs/arect/Android.bp libs/attestation/Android.bp libs/attestation/tests/Android.bp libs/binder/Android.bp libs/binder/ndk/Android.bp libs/binder/ndk/tests/Android.bp libs/binder/parcel_fuzzer/Android.bp libs/binder/rust/Android.bp libs/binder/rust/tests/Android.bp libs/binder/tests/Android.bp libs/binder/tests/fuzzers/Android.bp libs/binderdebug/Android.bp libs/binderdebug/tests/Android.bp libs/binderthreadstate/1.0/Android.bp libs/binderthreadstate/Android.bp libs/bufferqueueconverter/Android.bp libs/cputimeinstate/Android.bp libs/diskusage/Android.bp libs/dumputils/Android.bp libs/fakeservicemanager/Android.bp libs/ftl/Android.bp libs/gralloc/types/Android.bp libs/gralloc/types/fuzzer/Android.bp libs/gralloc/types/tests/Android.bp libs/graphicsenv/Android.bp libs/gui/Android.bp libs/gui/sysprop/Android.bp libs/gui/tests/Android.bp libs/incidentcompanion/Android.bp libs/input/Android.bp libs/input/tests/Android.bp libs/math/Android.bp libs/math/tests/Android.bp libs/nativebase/Android.bp libs/nativedisplay/Android.bp libs/nativewindow/Android.bp libs/nativewindow/tests/Android.bp libs/renderengine/Android.bp libs/renderengine/tests/Android.bp libs/sensor/Android.bp libs/sensor/tests/Android.bp libs/sensorprivacy/Android.bp libs/ui/Android.bp libs/ui/tests/Android.bp libs/ui/tools/Android.bp libs/vibrator/Android.bp libs/vibrator/fuzzer/Android.bp libs/vr/libbroadcastring/Android.bp libs/vr/libbufferhub/Android.bp libs/vr/libbufferhubqueue/Android.bp libs/vr/libbufferhubqueue/benchmarks/Android.bp libs/vr/libbufferhubqueue/tests/Android.bp libs/vr/libdisplay/Android.bp libs/vr/libdvr/Android.bp libs/vr/libdvr/tests/Android.bp libs/vr/libdvrcommon/Android.bp libs/vr/libpdx/Android.bp libs/vr/libpdx/fuzz/Android.bp libs/vr/libpdx_default_transport/Android.bp libs/vr/libpdx_uds/Android.bp libs/vr/libperformance/Android.bp libs/vr/libvr_manager/Android.bp libs/vr/libvrflinger/Android.bp libs/vr/libvrflinger/tests/Android.bp libs/vr/libvrsensor/Android.bp opengl/libs/Android.bp opengl/tests/EGLTest/Android.bp opengl/tests/configdump/Android.bp opengl/tests/fillrate/Android.bp opengl/tests/filter/Android.bp opengl/tests/finish/Android.bp opengl/tests/gl2_basic/Android.bp opengl/tests/gl2_cameraeye/Android.bp opengl/tests/gl2_copyTexImage/Android.bp opengl/tests/gl2_java/Android.bp opengl/tests/gl2_jni/Android.bp opengl/tests/gl2_yuvtex/Android.bp opengl/tests/gl_basic/Android.bp opengl/tests/gl_jni/Android.bp opengl/tests/gl_perf/Android.bp opengl/tests/gl_perfapp/Android.bp opengl/tests/gl_yuvtex/Android.bp opengl/tests/gldual/Android.bp opengl/tests/gralloc/Android.bp opengl/tests/hwc/Android.bp opengl/tests/lib/Android.bp opengl/tests/lighting1709/Android.bp opengl/tests/linetex/Android.bp opengl/tests/swapinterval/Android.bp opengl/tests/testFramerate/Android.bp opengl/tests/testLatency/Android.bp opengl/tests/testPauseResume/Android.bp opengl/tests/testViewport/Android.bp opengl/tests/textures/Android.bp opengl/tests/tritex/Android.bp services/audiomanager/Android.bp services/automotive/display/Android.bp services/batteryservice/Android.bp services/displayservice/Android.bp services/gpuservice/Android.bp services/gpuservice/bpfprogs/Android.bp services/gpuservice/gpumem/Android.bp services/gpuservice/gpustats/Android.bp services/gpuservice/tests/unittests/Android.bp services/gpuservice/tracing/Android.bp services/inputflinger/Android.bp services/inputflinger/benchmarks/Android.bp services/inputflinger/dispatcher/Android.bp services/inputflinger/host/Android.bp services/inputflinger/reader/Android.bp services/inputflinger/reporter/Android.bp services/inputflinger/tests/Android.bp services/powermanager/Android.bp services/powermanager/benchmarks/Android.bp services/powermanager/tests/Android.bp services/schedulerservice/Android.bp services/sensorservice/Android.bp services/sensorservice/hidl/Android.bp services/sensorservice/tests/Android.bp services/stats/Android.bp services/surfaceflinger/Android.bp services/surfaceflinger/CompositionEngine/Android.bp services/surfaceflinger/FrameTimeline/Android.bp services/surfaceflinger/TimeStats/Android.bp services/surfaceflinger/TimeStats/timestatsproto/Android.bp services/surfaceflinger/layerproto/Android.bp services/surfaceflinger/sysprop/Android.bp services/surfaceflinger/tests/Android.bp services/surfaceflinger/tests/fakehwc/Android.bp services/surfaceflinger/tests/unittests/Android.bp services/surfaceflinger/tests/vsync/Android.bp services/surfaceflinger/tests/waitforvsync/Android.bp services/utils/Android.bp services/utils/tests/Android.bp services/vibratorservice/Android.bp services/vibratorservice/benchmarks/Android.bp services/vibratorservice/test/Android.bp services/vr/bufferhubd/Android.bp services/vr/hardware_composer/Android.bp services/vr/hardware_composer/aidl/Android.bp services/vr/virtual_touchpad/Android.bp vulkan/libvulkan/Android.bp vulkan/nulldrv/Android.bp vulkan/vkjson/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-MIT SPDX-license-identifier-Unicode-DFS legacy_notice to: Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-MIT legacy_notice to: opengl/Android.bp opengl/tests/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD legacy_notice to: libs/vr/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-MIT to: headers/Android.bp services/vr/Android.bp vulkan/Android.bp Added SPDX-license-identifier-BSD SPDX-license-identifier-MIT legacy_notice to: opengl/tests/angeles/Android.bp Added SPDX-license-identifier-MIT to: services/vr/performanced/Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: Ia0a5896316bc000a016f67939fe01a7336f2708c --- Android.bp | 40 ++++++++++++++++++- cmds/atrace/Android.bp | 17 ++++++++ cmds/bugreport/Android.bp | 9 +++++ cmds/bugreportz/Android.bp | 9 +++++ cmds/cmd/Android.bp | 17 ++++++++ cmds/dumpstate/Android.bp | 9 +++++ cmds/dumpsys/Android.bp | 17 ++++++++ cmds/dumpsys/tests/Android.bp | 9 +++++ cmds/flatland/Android.mk | 3 ++ cmds/idlcli/Android.bp | 9 +++++ cmds/installd/Android.bp | 9 +++++ cmds/installd/tests/Android.bp | 10 ++++- cmds/ip-up-vpn/Android.mk | 3 ++ cmds/lshal/Android.bp | 9 +++++ cmds/lshal/libprocpartition/Android.bp | 9 +++++ cmds/rawbu/Android.bp | 17 ++++++++ cmds/rss_hwm_reset/Android.bp | 9 +++++ cmds/service/Android.bp | 17 ++++++++ cmds/servicemanager/Android.bp | 9 +++++ cmds/surfacereplayer/Android.bp | 11 +++++- cmds/surfacereplayer/proto/Android.bp | 9 +++++ cmds/surfacereplayer/replayer/Android.bp | 9 +++++ data/etc/Android.bp | 11 +++++- headers/Android.bp | 10 +++++ libs/adbd_auth/Android.bp | 9 +++++ libs/android_runtime_lazy/Android.bp | 9 +++++ libs/arect/Android.bp | 17 ++++++++ libs/attestation/Android.bp | 11 +++++- libs/attestation/tests/Android.bp | 9 +++++ libs/binder/Android.bp | 9 +++++ libs/binder/ndk/Android.bp | 17 ++++++++ libs/binder/ndk/tests/Android.bp | 9 +++++ libs/binder/parcel_fuzzer/Android.bp | 9 +++++ libs/binder/rust/Android.bp | 9 +++++ libs/binder/rust/tests/Android.bp | 9 +++++ libs/binder/tests/Android.bp | 9 +++++ libs/binder/tests/fuzzers/Android.bp | 9 +++++ libs/binderdebug/Android.bp | 9 +++++ libs/binderdebug/tests/Android.bp | 9 +++++ libs/binderthreadstate/1.0/Android.bp | 9 +++++ libs/binderthreadstate/Android.bp | 9 +++++ libs/bufferqueueconverter/Android.bp | 9 +++++ libs/cputimeinstate/Android.bp | 10 ++++- libs/diskusage/Android.bp | 9 +++++ libs/dumputils/Android.bp | 9 +++++ libs/fakeservicemanager/Android.bp | 9 +++++ libs/ftl/Android.bp | 9 +++++ libs/gralloc/types/Android.bp | 9 +++++ libs/gralloc/types/fuzzer/Android.bp | 9 +++++ libs/gralloc/types/tests/Android.bp | 9 +++++ libs/graphicsenv/Android.bp | 9 +++++ libs/gui/Android.bp | 9 +++++ libs/gui/sysprop/Android.bp | 9 +++++ libs/gui/tests/Android.bp | 9 +++++ libs/incidentcompanion/Android.bp | 10 ++++- libs/input/Android.bp | 9 +++++ libs/input/tests/Android.bp | 9 +++++ libs/math/Android.bp | 17 ++++++++ libs/math/tests/Android.bp | 9 +++++ libs/nativebase/Android.bp | 17 ++++++++ libs/nativedisplay/Android.bp | 19 +++++++++ libs/nativewindow/Android.bp | 19 +++++++++ libs/nativewindow/tests/Android.bp | 11 ++++++ libs/renderengine/Android.bp | 9 +++++ libs/renderengine/tests/Android.bp | 9 +++++ libs/sensor/Android.bp | 9 +++++ libs/sensor/tests/Android.bp | 9 +++++ libs/sensorprivacy/Android.bp | 9 +++++ libs/ui/Android.bp | 17 ++++++++ libs/ui/tests/Android.bp | 9 +++++ libs/ui/tools/Android.bp | 9 +++++ libs/vibrator/Android.bp | 9 +++++ libs/vibrator/fuzzer/Android.bp | 9 +++++ libs/vr/Android.bp | 11 ++++++ libs/vr/libbroadcastring/Android.bp | 9 +++++ libs/vr/libbufferhub/Android.bp | 9 +++++ libs/vr/libbufferhubqueue/Android.bp | 9 +++++ libs/vr/libbufferhubqueue/benchmarks/Android.bp | 9 +++++ libs/vr/libbufferhubqueue/tests/Android.bp | 9 +++++ libs/vr/libdisplay/Android.bp | 9 +++++ libs/vr/libdvr/Android.bp | 9 +++++ libs/vr/libdvr/tests/Android.bp | 9 +++++ libs/vr/libdvrcommon/Android.bp | 9 +++++ libs/vr/libpdx/Android.bp | 9 +++++ libs/vr/libpdx/fuzz/Android.bp | 9 +++++ libs/vr/libpdx_default_transport/Android.bp | 10 ++++- libs/vr/libpdx_uds/Android.bp | 9 +++++ libs/vr/libperformance/Android.bp | 9 +++++ libs/vr/libvr_manager/Android.bp | 9 +++++ libs/vr/libvrflinger/Android.bp | 9 +++++ libs/vr/libvrflinger/tests/Android.bp | 9 +++++ libs/vr/libvrsensor/Android.bp | 10 ++++- opengl/Android.bp | 12 ++++++ opengl/libs/Android.bp | 9 +++++ opengl/tests/Android.bp | 13 ++++++- opengl/tests/EGLTest/Android.bp | 9 +++++ opengl/tests/angeles/Android.bp | 45 ++++++++++++++++++++++ opengl/tests/configdump/Android.bp | 9 +++++ opengl/tests/fillrate/Android.bp | 9 +++++ opengl/tests/filter/Android.bp | 9 +++++ opengl/tests/finish/Android.bp | 9 +++++ opengl/tests/gl2_basic/Android.bp | 9 +++++ opengl/tests/gl2_cameraeye/Android.bp | 9 +++++ opengl/tests/gl2_copyTexImage/Android.bp | 9 +++++ opengl/tests/gl2_java/Android.bp | 9 +++++ opengl/tests/gl2_jni/Android.bp | 9 +++++ opengl/tests/gl2_yuvtex/Android.bp | 9 +++++ opengl/tests/gl_basic/Android.bp | 9 +++++ opengl/tests/gl_jni/Android.bp | 9 +++++ opengl/tests/gl_perf/Android.bp | 9 +++++ opengl/tests/gl_perfapp/Android.bp | 9 +++++ opengl/tests/gl_yuvtex/Android.bp | 9 +++++ opengl/tests/gldual/Android.bp | 9 +++++ opengl/tests/gralloc/Android.bp | 9 +++++ opengl/tests/hwc/Android.bp | 9 +++++ opengl/tests/lib/Android.bp | 9 +++++ opengl/tests/lighting1709/Android.bp | 9 +++++ opengl/tests/linetex/Android.bp | 9 +++++ opengl/tests/swapinterval/Android.bp | 9 +++++ opengl/tests/testFramerate/Android.bp | 9 +++++ opengl/tests/testLatency/Android.bp | 9 +++++ opengl/tests/testPauseResume/Android.bp | 9 +++++ opengl/tests/testViewport/Android.bp | 9 +++++ opengl/tests/textures/Android.bp | 9 +++++ opengl/tests/tritex/Android.bp | 9 +++++ services/audiomanager/Android.bp | 9 +++++ services/automotive/display/Android.bp | 9 +++++ services/batteryservice/Android.bp | 9 +++++ services/displayservice/Android.bp | 9 +++++ services/gpuservice/Android.bp | 9 +++++ services/gpuservice/bpfprogs/Android.bp | 9 +++++ services/gpuservice/gpumem/Android.bp | 9 +++++ services/gpuservice/gpustats/Android.bp | 9 +++++ services/gpuservice/tests/unittests/Android.bp | 9 +++++ services/gpuservice/tracing/Android.bp | 9 +++++ services/inputflinger/Android.bp | 9 +++++ services/inputflinger/benchmarks/Android.bp | 9 +++++ services/inputflinger/dispatcher/Android.bp | 9 +++++ services/inputflinger/host/Android.bp | 9 +++++ services/inputflinger/reader/Android.bp | 9 +++++ services/inputflinger/reporter/Android.bp | 10 ++++- services/inputflinger/tests/Android.bp | 9 +++++ services/powermanager/Android.bp | 9 +++++ services/powermanager/benchmarks/Android.bp | 9 +++++ services/powermanager/tests/Android.bp | 9 +++++ services/schedulerservice/Android.bp | 9 +++++ services/sensorservice/Android.bp | 9 +++++ services/sensorservice/hidl/Android.bp | 9 +++++ services/sensorservice/tests/Android.bp | 9 +++++ services/stats/Android.bp | 9 +++++ services/surfaceflinger/Android.bp | 9 +++++ .../surfaceflinger/CompositionEngine/Android.bp | 9 +++++ services/surfaceflinger/FrameTimeline/Android.bp | 9 +++++ services/surfaceflinger/TimeStats/Android.bp | 9 +++++ .../TimeStats/timestatsproto/Android.bp | 9 +++++ services/surfaceflinger/layerproto/Android.bp | 9 +++++ services/surfaceflinger/sysprop/Android.bp | 9 +++++ services/surfaceflinger/tests/Android.bp | 9 +++++ services/surfaceflinger/tests/fakehwc/Android.bp | 9 +++++ services/surfaceflinger/tests/unittests/Android.bp | 9 +++++ services/surfaceflinger/tests/vsync/Android.bp | 9 +++++ .../surfaceflinger/tests/waitforvsync/Android.bp | 9 +++++ services/utils/Android.bp | 9 +++++ services/utils/tests/Android.bp | 9 +++++ services/vibratorservice/Android.bp | 9 +++++ services/vibratorservice/benchmarks/Android.bp | 9 +++++ services/vibratorservice/test/Android.bp | 9 +++++ services/vr/Android.bp | 10 +++++ services/vr/bufferhubd/Android.bp | 9 +++++ services/vr/hardware_composer/Android.bp | 9 +++++ services/vr/hardware_composer/aidl/Android.bp | 9 +++++ services/vr/performanced/Android.bp | 9 +++++ services/vr/virtual_touchpad/Android.bp | 9 +++++ vulkan/Android.bp | 10 +++++ vulkan/libvulkan/Android.bp | 9 +++++ vulkan/nulldrv/Android.bp | 9 +++++ vulkan/vkjson/Android.bp | 9 +++++ 177 files changed, 1763 insertions(+), 11 deletions(-) diff --git a/Android.bp b/Android.bp index f714759732..1393f61edc 100644 --- a/Android.bp +++ b/Android.bp @@ -1,3 +1,41 @@ +package { + default_applicable_licenses: ["frameworks_native_license"], +} + +// Added automatically by a large-scale-change that took the approach of +// 'apply every license found to every target'. While this makes sure we respect +// every license restriction, it may not be entirely correct. +// +// e.g. GPL in an MIT project might only apply to the contrib/ directory. +// +// Please consider splitting the single license below into multiple licenses, +// taking care not to lose any license_kind information, and overriding the +// default license using the 'licenses: [...]' property on targets as needed. +// +// For unused files, consider creating a 'fileGroup' with "//visibility:private" +// to attach the license to, and including a comment whether the files may be +// used in the current project. +// +// large-scale-change filtered out the below license kinds as false-positives: +// SPDX-license-identifier-LGPL +// SPDX-license-identifier-LGPL-2.1 +// SPDX-license-identifier-LGPL-3.0 +// See: http://go/android-license-faq +license { + name: "frameworks_native_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + "SPDX-license-identifier-BSD", + "SPDX-license-identifier-MIT", + "SPDX-license-identifier-Unicode-DFS", + "legacy_notice", + ], + license_text: [ + "NOTICE", + ], +} + ndk_headers { name: "libandroid_headers", from: "include/android", @@ -47,4 +85,4 @@ filegroup { cc_library_headers{ name: "libandroid_headers_private", export_include_dirs: ["include/private"], -} \ No newline at end of file +} diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp index e7d0ad0549..aa0ef253bf 100644 --- a/cmds/atrace/Android.bp +++ b/cmds/atrace/Android.bp @@ -1,5 +1,22 @@ // Copyright 2012 The Android Open Source Project +package { + default_applicable_licenses: ["frameworks_native_cmds_atrace_license"], +} + +// Added automatically by a large-scale-change +// See: http://go/android-license-faq +license { + name: "frameworks_native_cmds_atrace_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + ], + license_text: [ + "NOTICE", + ], +} + cc_binary { name: "atrace", srcs: ["atrace.cpp"], diff --git a/cmds/bugreport/Android.bp b/cmds/bugreport/Android.bp index 24044a64b0..8262aed97b 100644 --- a/cmds/bugreport/Android.bp +++ b/cmds/bugreport/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_binary { name: "bugreport", srcs: ["bugreport.cpp"], diff --git a/cmds/bugreportz/Android.bp b/cmds/bugreportz/Android.bp index 924a3a351b..332f858e92 100644 --- a/cmds/bugreportz/Android.bp +++ b/cmds/bugreportz/Android.bp @@ -1,5 +1,14 @@ // bugreportz // ========== +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_binary { name: "bugreportz", diff --git a/cmds/cmd/Android.bp b/cmds/cmd/Android.bp index 8ea71cd048..c900a24e15 100644 --- a/cmds/cmd/Android.bp +++ b/cmds/cmd/Android.bp @@ -1,3 +1,20 @@ +package { + default_applicable_licenses: ["frameworks_native_cmds_cmd_license"], +} + +// Added automatically by a large-scale-change +// See: http://go/android-license-faq +license { + name: "frameworks_native_cmds_cmd_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + ], + license_text: [ + "NOTICE", + ], +} + cc_library_static { name: "libcmd", diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp index 34e9a85af3..f48f1fb6f8 100644 --- a/cmds/dumpstate/Android.bp +++ b/cmds/dumpstate/Android.bp @@ -13,6 +13,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_defaults { name: "dumpstate_cflag_defaults", cflags: [ diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp index f99588ffc8..91aa018451 100644 --- a/cmds/dumpsys/Android.bp +++ b/cmds/dumpsys/Android.bp @@ -1,3 +1,20 @@ +package { + default_applicable_licenses: ["frameworks_native_cmds_dumpsys_license"], +} + +// Added automatically by a large-scale-change +// See: http://go/android-license-faq +license { + name: "frameworks_native_cmds_dumpsys_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + ], + license_text: [ + "NOTICE", + ], +} + cc_defaults { name: "dumpsys_defaults", diff --git a/cmds/dumpsys/tests/Android.bp b/cmds/dumpsys/tests/Android.bp index e182b9d287..6854c7550e 100644 --- a/cmds/dumpsys/tests/Android.bp +++ b/cmds/dumpsys/tests/Android.bp @@ -1,4 +1,13 @@ // Build the unit tests for dumpsys +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_cmds_dumpsys_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_cmds_dumpsys_license"], +} + cc_test { name: "dumpsys_test", test_suites: ["device-tests"], diff --git a/cmds/flatland/Android.mk b/cmds/flatland/Android.mk index 7aa111c7ae..754a99caf6 100644 --- a/cmds/flatland/Android.mk +++ b/cmds/flatland/Android.mk @@ -11,6 +11,9 @@ LOCAL_SRC_FILES:= \ LOCAL_CFLAGS := -Wall -Werror LOCAL_MODULE:= flatland +LOCAL_LICENSE_KINDS:= SPDX-license-identifier-Apache-2.0 +LOCAL_LICENSE_CONDITIONS:= notice +LOCAL_NOTICE_FILE:= $(LOCAL_PATH)/../../NOTICE LOCAL_MODULE_TAGS := tests diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp index 72ffc94d22..c537fed25d 100644 --- a/cmds/idlcli/Android.bp +++ b/cmds/idlcli/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_defaults { name: "idlcli-defaults", shared_libs: [ diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp index cbe857aacb..5c2211ff9a 100644 --- a/cmds/installd/Android.bp +++ b/cmds/installd/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_defaults { name: "installd_defaults", diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp index 7c9e3b2e38..f67ab812fa 100644 --- a/cmds/installd/tests/Android.bp +++ b/cmds/installd/tests/Android.bp @@ -1,4 +1,13 @@ // Build the unit tests for installd +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "installd_utils_test", test_suites: ["device-tests"], @@ -157,4 +166,3 @@ cc_test { "libotapreoptparameters" ], } - diff --git a/cmds/ip-up-vpn/Android.mk b/cmds/ip-up-vpn/Android.mk index e1e2204233..396ae9db04 100644 --- a/cmds/ip-up-vpn/Android.mk +++ b/cmds/ip-up-vpn/Android.mk @@ -21,6 +21,9 @@ LOCAL_SRC_FILES := ip-up-vpn.c LOCAL_CFLAGS := -Wall -Werror LOCAL_SHARED_LIBRARIES := libcutils liblog LOCAL_MODULE := ip-up-vpn +LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 +LOCAL_LICENSE_CONDITIONS := notice +LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/ppp LOCAL_MODULE_TAGS := optional diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp index 0cbb80feb2..649e53a8aa 100644 --- a/cmds/lshal/Android.bp +++ b/cmds/lshal/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_static { name: "liblshal", shared_libs: [ diff --git a/cmds/lshal/libprocpartition/Android.bp b/cmds/lshal/libprocpartition/Android.bp index 9592111796..cbfbdc9223 100644 --- a/cmds/lshal/libprocpartition/Android.bp +++ b/cmds/lshal/libprocpartition/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_static { name: "libprocpartition", shared_libs: [ diff --git a/cmds/rawbu/Android.bp b/cmds/rawbu/Android.bp index 363ffc1aaf..e34119d1d1 100644 --- a/cmds/rawbu/Android.bp +++ b/cmds/rawbu/Android.bp @@ -1,5 +1,22 @@ // Copyright 2009 The Android Open Source Project +package { + default_applicable_licenses: ["frameworks_native_cmds_rawbu_license"], +} + +// Added automatically by a large-scale-change +// See: http://go/android-license-faq +license { + name: "frameworks_native_cmds_rawbu_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + ], + license_text: [ + "NOTICE", + ], +} + cc_binary { name: "rawbu", diff --git a/cmds/rss_hwm_reset/Android.bp b/cmds/rss_hwm_reset/Android.bp index 15f10efdee..cd335d44cc 100644 --- a/cmds/rss_hwm_reset/Android.bp +++ b/cmds/rss_hwm_reset/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_binary { name: "rss_hwm_reset", diff --git a/cmds/service/Android.bp b/cmds/service/Android.bp index a5b1ac5c5f..3e8e3f67f8 100644 --- a/cmds/service/Android.bp +++ b/cmds/service/Android.bp @@ -1,3 +1,20 @@ +package { + default_applicable_licenses: ["frameworks_native_cmds_service_license"], +} + +// Added automatically by a large-scale-change +// See: http://go/android-license-faq +license { + name: "frameworks_native_cmds_service_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + ], + license_text: [ + "NOTICE", + ], +} + cc_binary { name: "service", diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index b1392515a2..9de344a820 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_defaults { name: "servicemanager_defaults", diff --git a/cmds/surfacereplayer/Android.bp b/cmds/surfacereplayer/Android.bp index d4c037ab7d..34fc8b10ea 100644 --- a/cmds/surfacereplayer/Android.bp +++ b/cmds/surfacereplayer/Android.bp @@ -1,4 +1,13 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + subdirs = [ "proto", "replayer", -] \ No newline at end of file +] diff --git a/cmds/surfacereplayer/proto/Android.bp b/cmds/surfacereplayer/proto/Android.bp index 71a5e23a9e..23b54ee5b0 100644 --- a/cmds/surfacereplayer/proto/Android.bp +++ b/cmds/surfacereplayer/proto/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_static { name: "libtrace_proto", srcs: [ diff --git a/cmds/surfacereplayer/replayer/Android.bp b/cmds/surfacereplayer/replayer/Android.bp index 7632311906..3985230f08 100644 --- a/cmds/surfacereplayer/replayer/Android.bp +++ b/cmds/surfacereplayer/replayer/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_shared { name: "libsurfacereplayer", srcs: [ diff --git a/data/etc/Android.bp b/data/etc/Android.bp index 83b6aa020c..9d88ca64e6 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -1,7 +1,16 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + prebuilt_etc { name: "android.hardware.biometrics.face.xml", product_specific: true, sub_dir: "permissions", src: "android.hardware.biometrics.face.xml", filename_from_src: true, -} \ No newline at end of file +} diff --git a/headers/Android.bp b/headers/Android.bp index 8f41c2b75b..7481a230c3 100644 --- a/headers/Android.bp +++ b/headers/Android.bp @@ -1,3 +1,13 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + // SPDX-license-identifier-MIT + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_headers { name: "media_plugin_headers", vendor_available: true, diff --git a/libs/adbd_auth/Android.bp b/libs/adbd_auth/Android.bp index 8883c0478a..16cded8141 100644 --- a/libs/adbd_auth/Android.bp +++ b/libs/adbd_auth/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library { name: "libadbd_auth", cflags: [ diff --git a/libs/android_runtime_lazy/Android.bp b/libs/android_runtime_lazy/Android.bp index cdd776480c..b74923cbfc 100644 --- a/libs/android_runtime_lazy/Android.bp +++ b/libs/android_runtime_lazy/Android.bp @@ -30,6 +30,15 @@ // instead of libandroid_runtime. When they are used by a vendor process, // depending on libandroid_runtime is meaningless. In this case, // they can depend on libandroid_runtime_lazy. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library { name: "libandroid_runtime_lazy", vendor_available: true, diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp index 80aa8916da..bb40f5146e 100644 --- a/libs/arect/Android.bp +++ b/libs/arect/Android.bp @@ -12,6 +12,23 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["frameworks_native_libs_arect_license"], +} + +// Added automatically by a large-scale-change +// See: http://go/android-license-faq +license { + name: "frameworks_native_libs_arect_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + ], + license_text: [ + "NOTICE", + ], +} + ndk_headers { name: "libarect_headers_for_ndk", from: "include/android", diff --git a/libs/attestation/Android.bp b/libs/attestation/Android.bp index b85aecd16d..ea3c341fe4 100644 --- a/libs/attestation/Android.bp +++ b/libs/attestation/Android.bp @@ -11,6 +11,15 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_static { name: "libattestation", cflags: [ @@ -28,4 +37,4 @@ cc_library_static { "liblog", "libcrypto", ], -} \ No newline at end of file +} diff --git a/libs/attestation/tests/Android.bp b/libs/attestation/tests/Android.bp index 6ce5ea1b2d..8dac0ce0fc 100644 --- a/libs/attestation/tests/Android.bp +++ b/libs/attestation/tests/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "libattestation_tests", test_suites: ["device-tests"], diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index b585ad2c7b..e9d866b448 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_headers { name: "libbinder_headers", export_include_dirs: ["include"], diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp index 897c72a406..eb103d3d77 100644 --- a/libs/binder/ndk/Android.bp +++ b/libs/binder/ndk/Android.bp @@ -15,6 +15,23 @@ */ // TODO(b/31559095): bionic on host should define this +package { + default_applicable_licenses: ["frameworks_native_libs_binder_ndk_license"], +} + +// Added automatically by a large-scale-change +// See: http://go/android-license-faq +license { + name: "frameworks_native_libs_binder_ndk_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + ], + license_text: [ + "NOTICE", + ], +} + cc_defaults { name: "libbinder_ndk_host_user", target: { diff --git a/libs/binder/ndk/tests/Android.bp b/libs/binder/ndk/tests/Android.bp index 46e6270eb0..bb51bf0b5d 100644 --- a/libs/binder/ndk/tests/Android.bp +++ b/libs/binder/ndk/tests/Android.bp @@ -14,6 +14,15 @@ * limitations under the License. */ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_libs_binder_ndk_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_libs_binder_ndk_license"], +} + cc_defaults { name: "test_libbinder_ndk_defaults", shared_libs: [ diff --git a/libs/binder/parcel_fuzzer/Android.bp b/libs/binder/parcel_fuzzer/Android.bp index 3e6fe99541..74b8eb8d93 100644 --- a/libs/binder/parcel_fuzzer/Android.bp +++ b/libs/binder/parcel_fuzzer/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_fuzz { name: "binder_parcel_fuzzer", defaults: ["libbinder_ndk_host_user"], diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp index f804f1416a..e12a429cf9 100644 --- a/libs/binder/rust/Android.bp +++ b/libs/binder/rust/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + rust_library { name: "libbinder_rs", crate_name: "binder", diff --git a/libs/binder/rust/tests/Android.bp b/libs/binder/rust/tests/Android.bp index 8810b5dd16..0bf76c696a 100644 --- a/libs/binder/rust/tests/Android.bp +++ b/libs/binder/rust/tests/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + rust_test { name: "rustBinderTest", srcs: ["integration.rs"], diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 259417a655..3bbb0b52bb 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -14,6 +14,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_defaults { name: "binder_test_defaults", cflags: [ diff --git a/libs/binder/tests/fuzzers/Android.bp b/libs/binder/tests/fuzzers/Android.bp index 5531296edb..b1263e8d8e 100644 --- a/libs/binder/tests/fuzzers/Android.bp +++ b/libs/binder/tests/fuzzers/Android.bp @@ -14,6 +14,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_defaults { name: "binder_fuzz_defaults", host_supported: true, diff --git a/libs/binderdebug/Android.bp b/libs/binderdebug/Android.bp index 343246a324..3eeaf3e4f1 100644 --- a/libs/binderdebug/Android.bp +++ b/libs/binderdebug/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library { name: "libbinderdebug", vendor_available: true, diff --git a/libs/binderdebug/tests/Android.bp b/libs/binderdebug/tests/Android.bp index 4c06b1d0d9..d141a05ca9 100644 --- a/libs/binderdebug/tests/Android.bp +++ b/libs/binderdebug/tests/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "libbinderdebug_test", test_suites: ["general-tests"], diff --git a/libs/binderthreadstate/1.0/Android.bp b/libs/binderthreadstate/1.0/Android.bp index ebdc932591..99477d8e26 100644 --- a/libs/binderthreadstate/1.0/Android.bp +++ b/libs/binderthreadstate/1.0/Android.bp @@ -1,5 +1,14 @@ // This file is autogenerated by hidl-gen -Landroidbp. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + hidl_interface { name: "binderthreadstateutilstest@1.0", root: "binderthreadstateutilstest", diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp index 08c62df072..0a82463feb 100644 --- a/libs/binderthreadstate/Android.bp +++ b/libs/binderthreadstate/Android.bp @@ -14,6 +14,15 @@ // DO NOT ADD NEW USAGES OF THIS // See comments in header file. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_static { name: "libbinderthreadstateutils", double_loadable: true, diff --git a/libs/bufferqueueconverter/Android.bp b/libs/bufferqueueconverter/Android.bp index bab267466c..c5d3a3207c 100644 --- a/libs/bufferqueueconverter/Android.bp +++ b/libs/bufferqueueconverter/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_headers { name: "libbufferqueueconverter_headers", vendor_available: true, diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp index e3cd0859cb..570af71d9a 100644 --- a/libs/cputimeinstate/Android.bp +++ b/libs/cputimeinstate/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library { name: "libtimeinstate", srcs: ["cputimeinstate.cpp"], @@ -35,4 +44,3 @@ cc_test { ], require_root: true, } - diff --git a/libs/diskusage/Android.bp b/libs/diskusage/Android.bp index a8263069de..86840613e6 100644 --- a/libs/diskusage/Android.bp +++ b/libs/diskusage/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_static { name: "libdiskusage", srcs: ["dirsize.c"], diff --git a/libs/dumputils/Android.bp b/libs/dumputils/Android.bp index e403d36da1..acda402993 100644 --- a/libs/dumputils/Android.bp +++ b/libs/dumputils/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library { name: "libdumputils", diff --git a/libs/fakeservicemanager/Android.bp b/libs/fakeservicemanager/Android.bp index 76518c1286..47c0657bbd 100644 --- a/libs/fakeservicemanager/Android.bp +++ b/libs/fakeservicemanager/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_defaults { name: "fakeservicemanager_defaults", host_supported: true, diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 5bccaca42d..97626bec7d 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "ftl_test", test_suites: ["device-tests"], diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp index dd0ae30703..a0032aecb9 100644 --- a/libs/gralloc/types/Android.bp +++ b/libs/gralloc/types/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library { name: "libgralloctypes", defaults: ["libbinder_ndk_host_user"], diff --git a/libs/gralloc/types/fuzzer/Android.bp b/libs/gralloc/types/fuzzer/Android.bp index 8933dc323f..6689771a24 100644 --- a/libs/gralloc/types/fuzzer/Android.bp +++ b/libs/gralloc/types/fuzzer/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_fuzz { name: "libgralloctypes_fuzzer", defaults: ["libbinder_ndk_host_user"], diff --git a/libs/gralloc/types/tests/Android.bp b/libs/gralloc/types/tests/Android.bp index b939c1db59..66eb0aa2fe 100644 --- a/libs/gralloc/types/tests/Android.bp +++ b/libs/gralloc/types/tests/Android.bp @@ -14,6 +14,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "GrallocTypes_test", shared_libs: [ diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp index 642c5f2cc0..a96a07a9b8 100644 --- a/libs/graphicsenv/Android.bp +++ b/libs/graphicsenv/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_shared { name: "libgraphicsenv", diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index fa5044cc16..debd664aba 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -11,6 +11,15 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_headers { name: "libgui_headers", vendor_available: true, diff --git a/libs/gui/sysprop/Android.bp b/libs/gui/sysprop/Android.bp index 64b1eacaa2..bddb0ac5ee 100644 --- a/libs/gui/sysprop/Android.bp +++ b/libs/gui/sysprop/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + sysprop_library { name: "LibGuiProperties", srcs: ["*.sysprop"], diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index 53c13c8859..c801c6243a 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -2,6 +2,15 @@ // Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE) // to integrate with auto-test framework. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "libgui_test", test_suites: ["device-tests"], diff --git a/libs/incidentcompanion/Android.bp b/libs/incidentcompanion/Android.bp index 63411b9698..ef7f52318b 100644 --- a/libs/incidentcompanion/Android.bp +++ b/libs/incidentcompanion/Android.bp @@ -14,6 +14,15 @@ * limitations under the License. */ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + filegroup { name: "incidentcompanion_aidl", srcs: [ @@ -49,4 +58,3 @@ cc_library_static { "-Wunused-parameter", ], } - diff --git a/libs/input/Android.bp b/libs/input/Android.bp index fce3000a0f..425361004c 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -14,6 +14,15 @@ // libinput is partially built for the host (used by build time keymap validation tool) +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + filegroup { name: "inputconstants_aidl", srcs: [ diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index b23aaded78..fe8a5677d9 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -1,4 +1,13 @@ // Build the unit tests. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "libinput_tests", srcs: [ diff --git a/libs/math/Android.bp b/libs/math/Android.bp index 22d471204a..3cf9f3f97b 100644 --- a/libs/math/Android.bp +++ b/libs/math/Android.bp @@ -12,6 +12,23 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["frameworks_native_libs_math_license"], +} + +// Added automatically by a large-scale-change +// See: http://go/android-license-faq +license { + name: "frameworks_native_libs_math_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + ], + license_text: [ + "NOTICE", + ], +} + cc_library_static { name: "libmath", host_supported: true, diff --git a/libs/math/tests/Android.bp b/libs/math/tests/Android.bp index 0184f56dc4..4a7c4dd8a4 100644 --- a/libs/math/tests/Android.bp +++ b/libs/math/tests/Android.bp @@ -14,6 +14,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_libs_math_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_libs_math_license"], +} + cc_test { name: "vec_test", srcs: ["vec_test.cpp"], diff --git a/libs/nativebase/Android.bp b/libs/nativebase/Android.bp index 8399e8ce0a..1a4729c610 100644 --- a/libs/nativebase/Android.bp +++ b/libs/nativebase/Android.bp @@ -12,6 +12,23 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["frameworks_native_libs_nativebase_license"], +} + +// Added automatically by a large-scale-change +// See: http://go/android-license-faq +license { + name: "frameworks_native_libs_nativebase_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + ], + license_text: [ + "NOTICE", + ], +} + cc_library_headers { name: "libnativebase_headers", vendor_available: true, diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp index 6574ae64f7..ed728dcb45 100644 --- a/libs/nativedisplay/Android.bp +++ b/libs/nativedisplay/Android.bp @@ -12,6 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: [ + "frameworks_native_libs_nativedisplay_license", + ], +} + +// Added automatically by a large-scale-change +// See: http://go/android-license-faq +license { + name: "frameworks_native_libs_nativedisplay_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + ], + license_text: [ + "NOTICE", + ], +} + cc_library_headers { name: "libnativedisplay_headers", export_include_dirs: ["include",], diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp index 3011dccf1e..8675439938 100644 --- a/libs/nativewindow/Android.bp +++ b/libs/nativewindow/Android.bp @@ -12,6 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: [ + "frameworks_native_libs_nativewindow_license", + ], +} + +// Added automatically by a large-scale-change +// See: http://go/android-license-faq +license { + name: "frameworks_native_libs_nativewindow_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + ], + license_text: [ + "NOTICE", + ], +} + ndk_headers { name: "libnativewindow_ndk_headers", from: "include/android", diff --git a/libs/nativewindow/tests/Android.bp b/libs/nativewindow/tests/Android.bp index 2e4bd991e0..30737c1bf6 100644 --- a/libs/nativewindow/tests/Android.bp +++ b/libs/nativewindow/tests/Android.bp @@ -14,6 +14,17 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_libs_nativewindow_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: [ + "frameworks_native_libs_nativewindow_license", + ], +} + cc_test { name: "libnativewindow_test", test_suites: [ diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index 00540b8f68..eb3b434935 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_defaults { name: "renderengine_defaults", cflags: [ diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp index 51c702884b..d0e19dd4e2 100644 --- a/libs/renderengine/tests/Android.bp +++ b/libs/renderengine/tests/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "librenderengine_test", defaults: ["skia_deps", "surfaceflinger_defaults"], diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp index e8154a6931..497c33c386 100644 --- a/libs/sensor/Android.bp +++ b/libs/sensor/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_shared { name: "libsensor", diff --git a/libs/sensor/tests/Android.bp b/libs/sensor/tests/Android.bp index c9a7668563..8fdb003a5d 100644 --- a/libs/sensor/tests/Android.bp +++ b/libs/sensor/tests/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "libsensor_test", diff --git a/libs/sensorprivacy/Android.bp b/libs/sensorprivacy/Android.bp index 4a606ffec2..00514c4417 100644 --- a/libs/sensorprivacy/Android.bp +++ b/libs/sensorprivacy/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_shared { name: "libsensorprivacy", diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 714ee3e909..5982fa67e7 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -12,6 +12,23 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["frameworks_native_libs_ui_license"], +} + +// Added automatically by a large-scale-change +// See: http://go/android-license-faq +license { + name: "frameworks_native_libs_ui_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + ], + license_text: [ + "NOTICE", + ], +} + cc_defaults { name: "libui-defaults", clang: true, diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp index d005ce8e23..516aad824e 100644 --- a/libs/ui/tests/Android.bp +++ b/libs/ui/tests/Android.bp @@ -14,6 +14,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_libs_ui_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_libs_ui_license"], +} + cc_test { name: "Region_test", shared_libs: ["libui"], diff --git a/libs/ui/tools/Android.bp b/libs/ui/tools/Android.bp index fb46c2b20c..c28c303c0c 100644 --- a/libs/ui/tools/Android.bp +++ b/libs/ui/tools/Android.bp @@ -14,6 +14,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_libs_ui_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_libs_ui_license"], +} + cc_defaults { name: "libui_tools_default", clang_cflags: [ diff --git a/libs/vibrator/Android.bp b/libs/vibrator/Android.bp index 49bc6bf067..83c250a24f 100644 --- a/libs/vibrator/Android.bp +++ b/libs/vibrator/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library { name: "libvibrator", vendor_available: true, diff --git a/libs/vibrator/fuzzer/Android.bp b/libs/vibrator/fuzzer/Android.bp index 802015180e..f2a313cb8a 100644 --- a/libs/vibrator/fuzzer/Android.bp +++ b/libs/vibrator/fuzzer/Android.bp @@ -17,6 +17,15 @@ ***************************************************************************** */ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_fuzz { name: "vibrator_fuzzer", diff --git a/libs/vr/Android.bp b/libs/vr/Android.bp index e8176cf6b6..b308895faf 100644 --- a/libs/vr/Android.bp +++ b/libs/vr/Android.bp @@ -1,3 +1,14 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + // SPDX-license-identifier-BSD + // legacy_notice + default_applicable_licenses: ["frameworks_native_license"], +} + subdirs = [ "*", ] diff --git a/libs/vr/libbroadcastring/Android.bp b/libs/vr/libbroadcastring/Android.bp index 13af470a26..d4538f12a2 100644 --- a/libs/vr/libbroadcastring/Android.bp +++ b/libs/vr/libbroadcastring/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_static { name: "libbroadcastring", clang: true, diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp index 37c19d43f7..583ad1dd94 100644 --- a/libs/vr/libbufferhub/Android.bp +++ b/libs/vr/libbufferhub/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_headers { name: "libbufferhub_headers", export_include_dirs: ["include"], diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp index 77c79112de..0bda7987a0 100644 --- a/libs/vr/libbufferhubqueue/Android.bp +++ b/libs/vr/libbufferhubqueue/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + sourceFiles = [ "buffer_hub_queue_client.cpp", "buffer_hub_queue_parcelable.cpp", diff --git a/libs/vr/libbufferhubqueue/benchmarks/Android.bp b/libs/vr/libbufferhubqueue/benchmarks/Android.bp index ef1eed6d0a..e33e03b37b 100644 --- a/libs/vr/libbufferhubqueue/benchmarks/Android.bp +++ b/libs/vr/libbufferhubqueue/benchmarks/Android.bp @@ -1,4 +1,13 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_benchmark { srcs: ["buffer_transport_benchmark.cpp"], shared_libs: [ diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp index a33792177b..33a0d754c1 100644 --- a/libs/vr/libbufferhubqueue/tests/Android.bp +++ b/libs/vr/libbufferhubqueue/tests/Android.bp @@ -1,4 +1,13 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + header_libraries = [ "libdvr_headers", ] diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp index 8c354fbc18..b0ed950c51 100644 --- a/libs/vr/libdisplay/Android.bp +++ b/libs/vr/libdisplay/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + sourceFiles = [ "display_client.cpp", "display_manager_client.cpp", diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp index d5a19d3e6c..96023ddf86 100644 --- a/libs/vr/libdvr/Android.bp +++ b/libs/vr/libdvr/Android.bp @@ -13,6 +13,15 @@ // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_headers { name: "libdvr_headers", export_include_dirs: ["include"], diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp index 3260447390..fe7feb824d 100644 --- a/libs/vr/libdvr/tests/Android.bp +++ b/libs/vr/libdvr/tests/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { srcs: [ "dvr_display_manager-test.cpp", diff --git a/libs/vr/libdvrcommon/Android.bp b/libs/vr/libdvrcommon/Android.bp index e75176846e..fe4dfc792a 100644 --- a/libs/vr/libdvrcommon/Android.bp +++ b/libs/vr/libdvrcommon/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + localIncludeFiles = [ "include", ] diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp index 24ba83048d..c1f6da3b10 100644 --- a/libs/vr/libpdx/Android.bp +++ b/libs/vr/libpdx/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_headers { name: "libpdx_headers", export_include_dirs: ["private"], diff --git a/libs/vr/libpdx/fuzz/Android.bp b/libs/vr/libpdx/fuzz/Android.bp index b36e0deea0..cc32b1822b 100644 --- a/libs/vr/libpdx/fuzz/Android.bp +++ b/libs/vr/libpdx/fuzz/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_fuzz { name: "libpdx_service_dispatcher_fuzzer", clang: true, diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp index b3534de101..804685747e 100644 --- a/libs/vr/libpdx_default_transport/Android.bp +++ b/libs/vr/libpdx_default_transport/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_defaults { name: "pdx_default_transport_compiler_defaults", clang: true, @@ -75,4 +84,3 @@ cc_binary { "libpdx_default_transport", ], } - diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp index 1d6eea29a6..216ca9f236 100644 --- a/libs/vr/libpdx_uds/Android.bp +++ b/libs/vr/libpdx_uds/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_static { name: "libpdx_uds", clang: true, diff --git a/libs/vr/libperformance/Android.bp b/libs/vr/libperformance/Android.bp index 35d3dea9de..38bf4ea522 100644 --- a/libs/vr/libperformance/Android.bp +++ b/libs/vr/libperformance/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + sourceFiles = [ "performance_client.cpp", "performance_rpc.cpp", diff --git a/libs/vr/libvr_manager/Android.bp b/libs/vr/libvr_manager/Android.bp index 2cd6a28e2f..6f2ada4633 100644 --- a/libs/vr/libvr_manager/Android.bp +++ b/libs/vr/libvr_manager/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_static { name: "libvr_manager", srcs: [ diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp index abc64bde5a..bf848af262 100644 --- a/libs/vr/libvrflinger/Android.bp +++ b/libs/vr/libvrflinger/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + sourceFiles = [ "acquired_buffer.cpp", "epoll_event_dispatcher.cpp", diff --git a/libs/vr/libvrflinger/tests/Android.bp b/libs/vr/libvrflinger/tests/Android.bp index 7fafd3bf50..095f556609 100644 --- a/libs/vr/libvrflinger/tests/Android.bp +++ b/libs/vr/libvrflinger/tests/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + shared_libs = [ "android.hardware.configstore-utils", "android.hardware.configstore@1.0", diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp index 85427906f1..40a5099177 100644 --- a/libs/vr/libvrsensor/Android.bp +++ b/libs/vr/libvrsensor/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + sourceFiles = [ "pose_client.cpp", "latency_model.cpp", @@ -52,4 +61,3 @@ cc_library { header_libs: ["libdvr_headers"], name: "libvrsensor", } - diff --git a/opengl/Android.bp b/opengl/Android.bp index 8b94f616c6..3878cb1899 100644 --- a/opengl/Android.bp +++ b/opengl/Android.bp @@ -12,6 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + // SPDX-license-identifier-BSD + // SPDX-license-identifier-MIT + // legacy_notice + default_applicable_licenses: ["frameworks_native_license"], +} + ndk_headers { name: "libEGL_headers", from: "include", diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index 5d17561248..7861d62311 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -1,4 +1,13 @@ // Build the ETC1 library +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library { name: "libETC1", srcs: ["ETC1/etc1.cpp"], diff --git a/opengl/tests/Android.bp b/opengl/tests/Android.bp index 639f351c69..da717bddf8 100644 --- a/opengl/tests/Android.bp +++ b/opengl/tests/Android.bp @@ -1,4 +1,16 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + // SPDX-license-identifier-BSD + // SPDX-license-identifier-MIT + // legacy_notice + default_applicable_licenses: ["frameworks_native_license"], +} + subdirs = [ "angeles", "configdump", @@ -16,4 +28,3 @@ subdirs = [ "hwc", "lib", ] - diff --git a/opengl/tests/EGLTest/Android.bp b/opengl/tests/EGLTest/Android.bp index e3912a84e6..51c937614f 100644 --- a/opengl/tests/EGLTest/Android.bp +++ b/opengl/tests/EGLTest/Android.bp @@ -1,4 +1,13 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "EGL_test", diff --git a/opengl/tests/angeles/Android.bp b/opengl/tests/angeles/Android.bp index 5c398a6323..5b81501241 100644 --- a/opengl/tests/angeles/Android.bp +++ b/opengl/tests/angeles/Android.bp @@ -1,5 +1,50 @@ // Copyright 2006 The Android Open Source Project +package { + default_applicable_licenses: [ + "frameworks_native_opengl_tests_angeles_license", + ], +} + +// Added automatically by a large-scale-change that took the approach of +// 'apply every license found to every target'. While this makes sure we respect +// every license restriction, it may not be entirely correct. +// +// e.g. GPL in an MIT project might only apply to the contrib/ directory. +// +// Please consider splitting the single license below into multiple licenses, +// taking care not to lose any license_kind information, and overriding the +// default license using the 'licenses: [...]' property on targets as needed. +// +// For unused files, consider creating a 'fileGroup' with "//visibility:private" +// to attach the license to, and including a comment whether the files may be +// used in the current project. +// +// large-scale-change included anything that looked like it might be a license +// text as a license_text. e.g. LICENSE, NOTICE, COPYING etc. +// +// Please consider removing redundant or irrelevant files from 'license_text:'. +// +// large-scale-change filtered out the below license kinds as false-positives: +// SPDX-license-identifier-LGPL +// SPDX-license-identifier-LGPL-2.1 +// SPDX-license-identifier-LGPL-3.0 +// See: http://go/android-license-faq +license { + name: "frameworks_native_opengl_tests_angeles_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-BSD", + "SPDX-license-identifier-MIT", + "legacy_notice", + ], + license_text: [ + "license-BSD.txt", + "license-LGPL.txt", + "license.txt", + ], +} + cc_test { name: "angeles", diff --git a/opengl/tests/configdump/Android.bp b/opengl/tests/configdump/Android.bp index ee96797030..1bb5983299 100644 --- a/opengl/tests/configdump/Android.bp +++ b/opengl/tests/configdump/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "test-opengl-configdump", diff --git a/opengl/tests/fillrate/Android.bp b/opengl/tests/fillrate/Android.bp index 689cee42d5..e4bff014fc 100644 --- a/opengl/tests/fillrate/Android.bp +++ b/opengl/tests/fillrate/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "test-opengl-fillrate", diff --git a/opengl/tests/filter/Android.bp b/opengl/tests/filter/Android.bp index 23241e1116..b93576fd0c 100644 --- a/opengl/tests/filter/Android.bp +++ b/opengl/tests/filter/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "test-opengl-filter", diff --git a/opengl/tests/finish/Android.bp b/opengl/tests/finish/Android.bp index be20851e8f..c2dfbc35b9 100644 --- a/opengl/tests/finish/Android.bp +++ b/opengl/tests/finish/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "test-opengl-finish", diff --git a/opengl/tests/gl2_basic/Android.bp b/opengl/tests/gl2_basic/Android.bp index f4538adb54..c54bdf335d 100644 --- a/opengl/tests/gl2_basic/Android.bp +++ b/opengl/tests/gl2_basic/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "test-opengl-gl2_basic", diff --git a/opengl/tests/gl2_cameraeye/Android.bp b/opengl/tests/gl2_cameraeye/Android.bp index 00e00dfc91..6b8ee85d9c 100644 --- a/opengl/tests/gl2_cameraeye/Android.bp +++ b/opengl/tests/gl2_cameraeye/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + android_app { name: "GL2CameraEye", // Only compile source java files in this apk. diff --git a/opengl/tests/gl2_copyTexImage/Android.bp b/opengl/tests/gl2_copyTexImage/Android.bp index 87fa7ea37d..0a84d254a5 100644 --- a/opengl/tests/gl2_copyTexImage/Android.bp +++ b/opengl/tests/gl2_copyTexImage/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "test-opengl-gl2_copyTexImage", diff --git a/opengl/tests/gl2_java/Android.bp b/opengl/tests/gl2_java/Android.bp index a8e5d7d70b..a33075e3b7 100644 --- a/opengl/tests/gl2_java/Android.bp +++ b/opengl/tests/gl2_java/Android.bp @@ -1,6 +1,15 @@ //######################################################################## // OpenGL ES 2.0 Java sample //######################################################################## +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + android_app { name: "GL2Java", srcs: ["**/*.java"], diff --git a/opengl/tests/gl2_jni/Android.bp b/opengl/tests/gl2_jni/Android.bp index 8d4323f9ca..79773cb05f 100644 --- a/opengl/tests/gl2_jni/Android.bp +++ b/opengl/tests/gl2_jni/Android.bp @@ -3,6 +3,15 @@ // This makefile builds both an activity and a shared library. //######################################################################## +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + android_app { name: "GL2JNI", srcs: ["**/*.java"], diff --git a/opengl/tests/gl2_yuvtex/Android.bp b/opengl/tests/gl2_yuvtex/Android.bp index b64d94d320..fadf0e8fc5 100644 --- a/opengl/tests/gl2_yuvtex/Android.bp +++ b/opengl/tests/gl2_yuvtex/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "test-opengl-gl2_yuvtex", diff --git a/opengl/tests/gl_basic/Android.bp b/opengl/tests/gl_basic/Android.bp index 5eed17e876..f55cd0dfe5 100644 --- a/opengl/tests/gl_basic/Android.bp +++ b/opengl/tests/gl_basic/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "test-opengl-gl_basic", diff --git a/opengl/tests/gl_jni/Android.bp b/opengl/tests/gl_jni/Android.bp index 0cb129a117..dc46483551 100644 --- a/opengl/tests/gl_jni/Android.bp +++ b/opengl/tests/gl_jni/Android.bp @@ -4,6 +4,15 @@ //######################################################################## // Build activity +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + android_app { name: "GLJNI", srcs: ["**/*.java"], diff --git a/opengl/tests/gl_perf/Android.bp b/opengl/tests/gl_perf/Android.bp index 25a317c3e3..ca0f7e8e33 100644 --- a/opengl/tests/gl_perf/Android.bp +++ b/opengl/tests/gl_perf/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "test-opengl-gl2_perf", diff --git a/opengl/tests/gl_perfapp/Android.bp b/opengl/tests/gl_perfapp/Android.bp index 66afb6a82c..2f623462cf 100644 --- a/opengl/tests/gl_perfapp/Android.bp +++ b/opengl/tests/gl_perfapp/Android.bp @@ -2,6 +2,15 @@ // OpenGL ES Perf App // This makefile builds both an activity and a shared library. //######################################################################## +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + android_app { name: "GLPerf", srcs: ["**/*.java"], diff --git a/opengl/tests/gl_yuvtex/Android.bp b/opengl/tests/gl_yuvtex/Android.bp index 9b4924ab82..784418679c 100644 --- a/opengl/tests/gl_yuvtex/Android.bp +++ b/opengl/tests/gl_yuvtex/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "test-opengl-gl_yuvtex", diff --git a/opengl/tests/gldual/Android.bp b/opengl/tests/gldual/Android.bp index 1006d44e47..3d6e677f0d 100644 --- a/opengl/tests/gldual/Android.bp +++ b/opengl/tests/gldual/Android.bp @@ -4,6 +4,15 @@ //######################################################################## // Build activity +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + android_app { name: "GLDual", srcs: ["**/*.java"], diff --git a/opengl/tests/gralloc/Android.bp b/opengl/tests/gralloc/Android.bp index 33c3dbaa17..5fb4556697 100644 --- a/opengl/tests/gralloc/Android.bp +++ b/opengl/tests/gralloc/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "test-opengl-gralloc", diff --git a/opengl/tests/hwc/Android.bp b/opengl/tests/hwc/Android.bp index 55f058f922..719eb114a1 100644 --- a/opengl/tests/hwc/Android.bp +++ b/opengl/tests/hwc/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_defaults { name: "hwc_tests_defaults", diff --git a/opengl/tests/lib/Android.bp b/opengl/tests/lib/Android.bp index 2f6095d8e7..05c9397dfa 100644 --- a/opengl/tests/lib/Android.bp +++ b/opengl/tests/lib/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_static { name: "libglTest", diff --git a/opengl/tests/lighting1709/Android.bp b/opengl/tests/lighting1709/Android.bp index e734dd1d2c..79daa26096 100644 --- a/opengl/tests/lighting1709/Android.bp +++ b/opengl/tests/lighting1709/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + android_test { name: "LightingTest", srcs: ["**/*.java"], diff --git a/opengl/tests/linetex/Android.bp b/opengl/tests/linetex/Android.bp index dbc2cdbd44..61976e599f 100644 --- a/opengl/tests/linetex/Android.bp +++ b/opengl/tests/linetex/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_binary { name: "test-opengl-linetex", srcs: ["linetex.cpp"], diff --git a/opengl/tests/swapinterval/Android.bp b/opengl/tests/swapinterval/Android.bp index eed4dff3a5..a76f4cfb9a 100644 --- a/opengl/tests/swapinterval/Android.bp +++ b/opengl/tests/swapinterval/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_binary { name: "test-opengl-swapinterval", srcs: ["swapinterval.cpp"], diff --git a/opengl/tests/testFramerate/Android.bp b/opengl/tests/testFramerate/Android.bp index 5aa83b0753..4334d88749 100644 --- a/opengl/tests/testFramerate/Android.bp +++ b/opengl/tests/testFramerate/Android.bp @@ -2,6 +2,15 @@ // Test framerate and look for hiccups //######################################################################## +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + android_app { name: "TestFramerate", srcs: ["**/*.java"], diff --git a/opengl/tests/testLatency/Android.bp b/opengl/tests/testLatency/Android.bp index c516dc3d17..473cb426cf 100644 --- a/opengl/tests/testLatency/Android.bp +++ b/opengl/tests/testLatency/Android.bp @@ -1,6 +1,15 @@ //######################################################################## // Test end-to-end latency. //######################################################################## +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + android_app { name: "TestLatency", sdk_version: "8", diff --git a/opengl/tests/testPauseResume/Android.bp b/opengl/tests/testPauseResume/Android.bp index 810e895ce2..8171e1fc8e 100644 --- a/opengl/tests/testPauseResume/Android.bp +++ b/opengl/tests/testPauseResume/Android.bp @@ -1,4 +1,13 @@ // OpenGL ES JNI sample +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + android_app { name: "TestEGL", srcs: ["**/*.java"], diff --git a/opengl/tests/testViewport/Android.bp b/opengl/tests/testViewport/Android.bp index 629b573a2a..13ce3ad481 100644 --- a/opengl/tests/testViewport/Android.bp +++ b/opengl/tests/testViewport/Android.bp @@ -2,6 +2,15 @@ // OpenGL ES JNI sample // This makefile builds both an activity and a shared library. //######################################################################## +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + android_app { name: "TestViewport", srcs: ["**/*.java"], diff --git a/opengl/tests/textures/Android.bp b/opengl/tests/textures/Android.bp index 84adda2aa4..f113ff78d2 100644 --- a/opengl/tests/textures/Android.bp +++ b/opengl/tests/textures/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_binary { name: "test-opengl-textures", srcs: ["textures.cpp"], diff --git a/opengl/tests/tritex/Android.bp b/opengl/tests/tritex/Android.bp index 390397b9da..87da93f6bc 100644 --- a/opengl/tests/tritex/Android.bp +++ b/opengl/tests/tritex/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_binary { name: "test-opengl-tritex", srcs: ["tritex.cpp"], diff --git a/services/audiomanager/Android.bp b/services/audiomanager/Android.bp index 12ad47e15a..e6fb2c3660 100644 --- a/services/audiomanager/Android.bp +++ b/services/audiomanager/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_shared { name: "libaudiomanager", diff --git a/services/automotive/display/Android.bp b/services/automotive/display/Android.bp index c3da216002..72bd29254d 100644 --- a/services/automotive/display/Android.bp +++ b/services/automotive/display/Android.bp @@ -14,6 +14,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_binary { name: "android.frameworks.automotive.display@1.0-service", defaults: ["hidl_defaults"], diff --git a/services/batteryservice/Android.bp b/services/batteryservice/Android.bp index 66ee8ff55e..1e3799185e 100644 --- a/services/batteryservice/Android.bp +++ b/services/batteryservice/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_headers { name: "libbatteryservice_headers", vendor_available: true, diff --git a/services/displayservice/Android.bp b/services/displayservice/Android.bp index 4d2d87352b..8681784405 100644 --- a/services/displayservice/Android.bp +++ b/services/displayservice/Android.bp @@ -14,6 +14,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_shared { name: "libdisplayservicehidl", diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp index 9a9bca1478..b9b6a19606 100644 --- a/services/gpuservice/Android.bp +++ b/services/gpuservice/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_defaults { name: "gpuservice_defaults", cflags: [ diff --git a/services/gpuservice/bpfprogs/Android.bp b/services/gpuservice/bpfprogs/Android.bp index b8758146cc..9842ed7c3c 100644 --- a/services/gpuservice/bpfprogs/Android.bp +++ b/services/gpuservice/bpfprogs/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + bpf { name: "gpu_mem.o", srcs: ["gpu_mem.c"], diff --git a/services/gpuservice/gpumem/Android.bp b/services/gpuservice/gpumem/Android.bp index b2230b6c01..830e53d534 100644 --- a/services/gpuservice/gpumem/Android.bp +++ b/services/gpuservice/gpumem/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_shared { name: "libgpumem", srcs: [ diff --git a/services/gpuservice/gpustats/Android.bp b/services/gpuservice/gpustats/Android.bp index f52602ab78..54291ad6c6 100644 --- a/services/gpuservice/gpustats/Android.bp +++ b/services/gpuservice/gpustats/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_shared { name: "libgfxstats", srcs: [ diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp index 9606daacec..6d87c45921 100644 --- a/services/gpuservice/tests/unittests/Android.bp +++ b/services/gpuservice/tests/unittests/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "gpuservice_unittest", test_suites: ["device-tests"], diff --git a/services/gpuservice/tracing/Android.bp b/services/gpuservice/tracing/Android.bp index 919fed3cec..a1bc1edad8 100644 --- a/services/gpuservice/tracing/Android.bp +++ b/services/gpuservice/tracing/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_shared { name: "libgpumemtracer", srcs: [ diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index b640e9c761..9b98a17b4d 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -13,6 +13,15 @@ // limitations under the License. // Default flags to be used throughout all libraries in inputflinger. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_defaults { name: "inputflinger_defaults", cflags: [ diff --git a/services/inputflinger/benchmarks/Android.bp b/services/inputflinger/benchmarks/Android.bp index bd275a76c1..ea37f4d424 100644 --- a/services/inputflinger/benchmarks/Android.bp +++ b/services/inputflinger/benchmarks/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_benchmark { name: "inputflinger_benchmarks", srcs: [ diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp index e5b131e95e..393f649746 100644 --- a/services/inputflinger/dispatcher/Android.bp +++ b/services/inputflinger/dispatcher/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_headers { name: "libinputdispatcher_headers", export_include_dirs: [ diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp index 9e797e4862..18d0226818 100644 --- a/services/inputflinger/host/Android.bp +++ b/services/inputflinger/host/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_shared { name: "libinputflingerhost", diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp index 7f979f2bd3..518e295472 100644 --- a/services/inputflinger/reader/Android.bp +++ b/services/inputflinger/reader/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_headers { name: "libinputreader_headers", export_include_dirs: [ diff --git a/services/inputflinger/reporter/Android.bp b/services/inputflinger/reporter/Android.bp index fbc51dadc0..74307310c5 100644 --- a/services/inputflinger/reporter/Android.bp +++ b/services/inputflinger/reporter/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_headers { name: "libinputreporter_headers", export_include_dirs: ["."], @@ -46,4 +55,3 @@ cc_library_shared { "libinputreporter_headers", ], } - diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index 959dadc9ef..42b54c75b6 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "inputflinger_tests", defaults: [ diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp index 68f4f283ee..1d3e5b53fa 100644 --- a/services/powermanager/Android.bp +++ b/services/powermanager/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_shared { name: "libpowermanager", diff --git a/services/powermanager/benchmarks/Android.bp b/services/powermanager/benchmarks/Android.bp index ad93a653a3..a489253207 100644 --- a/services/powermanager/benchmarks/Android.bp +++ b/services/powermanager/benchmarks/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_benchmark { name: "libpowermanager_benchmarks", srcs: [ diff --git a/services/powermanager/tests/Android.bp b/services/powermanager/tests/Android.bp index 0f5037e7fb..69e4041aaa 100644 --- a/services/powermanager/tests/Android.bp +++ b/services/powermanager/tests/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "libpowermanager_test", test_suites: ["device-tests"], diff --git a/services/schedulerservice/Android.bp b/services/schedulerservice/Android.bp index 73802dbc9f..4ef72d0c83 100644 --- a/services/schedulerservice/Android.bp +++ b/services/schedulerservice/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_shared { name: "libschedulerservicehidl", srcs: [ diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp index 532a2e5a13..ca9ff7c8c3 100644 --- a/services/sensorservice/Android.bp +++ b/services/sensorservice/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + subdirs = [ "hidl" ] diff --git a/services/sensorservice/hidl/Android.bp b/services/sensorservice/hidl/Android.bp index 0e1af595f0..9bafb3cf95 100644 --- a/services/sensorservice/hidl/Android.bp +++ b/services/sensorservice/hidl/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_shared { name: "libsensorservicehidl", srcs: [ diff --git a/services/sensorservice/tests/Android.bp b/services/sensorservice/tests/Android.bp index d33c0ca59d..ddc03a17e1 100644 --- a/services/sensorservice/tests/Android.bp +++ b/services/sensorservice/tests/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_binary { name: "test-sensorservice", srcs: ["sensorservicetest.cpp"], diff --git a/services/stats/Android.bp b/services/stats/Android.bp index 1ce0524299..58e59938fd 100644 --- a/services/stats/Android.bp +++ b/services/stats/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_shared { name: "libstatshidl", srcs: [ diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 8f91c8c081..625f315b00 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_defaults { name: "surfaceflinger_defaults", cflags: [ diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 57dc60bbac..50bc5edfc6 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_defaults { name: "libcompositionengine_defaults", defaults: ["surfaceflinger_defaults"], diff --git a/services/surfaceflinger/FrameTimeline/Android.bp b/services/surfaceflinger/FrameTimeline/Android.bp index 1e6d21efe7..10a58333f9 100644 --- a/services/surfaceflinger/FrameTimeline/Android.bp +++ b/services/surfaceflinger/FrameTimeline/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_static { name: "libframetimeline", defaults: ["surfaceflinger_defaults"], diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp index 0a23da2e9c..62fddb4f47 100644 --- a/services/surfaceflinger/TimeStats/Android.bp +++ b/services/surfaceflinger/TimeStats/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library { name: "libtimestats", srcs: [ diff --git a/services/surfaceflinger/TimeStats/timestatsproto/Android.bp b/services/surfaceflinger/TimeStats/timestatsproto/Android.bp index 9481cac34d..972edaa30b 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/Android.bp +++ b/services/surfaceflinger/TimeStats/timestatsproto/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library { name: "libtimestats_proto", export_include_dirs: ["include"], diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp index e2a28a2ae5..c8a2b5eed6 100644 --- a/services/surfaceflinger/layerproto/Android.bp +++ b/services/surfaceflinger/layerproto/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library { name: "liblayers_proto", export_include_dirs: ["include"], diff --git a/services/surfaceflinger/sysprop/Android.bp b/services/surfaceflinger/sysprop/Android.bp index 7721d7d2b7..f5791195db 100644 --- a/services/surfaceflinger/sysprop/Android.bp +++ b/services/surfaceflinger/sysprop/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + sysprop_library { name: "SurfaceFlingerProperties", srcs: ["*.sysprop"], diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index 8142aad382..78187f7e9d 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "SurfaceFlinger_test", defaults: ["surfaceflinger_defaults"], diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp index 3535fbb1b4..2551a19b71 100644 --- a/services/surfaceflinger/tests/fakehwc/Android.bp +++ b/services/surfaceflinger/tests/fakehwc/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "sffakehwc_test", defaults: ["surfaceflinger_defaults"], diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index e55821f690..2ac6b092b5 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "libsurfaceflinger_unittest", defaults: ["surfaceflinger_defaults"], diff --git a/services/surfaceflinger/tests/vsync/Android.bp b/services/surfaceflinger/tests/vsync/Android.bp index 6a89945a92..bae9796598 100644 --- a/services/surfaceflinger/tests/vsync/Android.bp +++ b/services/surfaceflinger/tests/vsync/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_binary { name: "test-vsync-events", defaults: ["surfaceflinger_defaults"], diff --git a/services/surfaceflinger/tests/waitforvsync/Android.bp b/services/surfaceflinger/tests/waitforvsync/Android.bp index cb6d0fde0d..ffed4d77c7 100644 --- a/services/surfaceflinger/tests/waitforvsync/Android.bp +++ b/services/surfaceflinger/tests/waitforvsync/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_binary { name: "test-waitforvsync", cflags: [ diff --git a/services/utils/Android.bp b/services/utils/Android.bp index f3d2bc9766..81e1232e2c 100644 --- a/services/utils/Android.bp +++ b/services/utils/Android.bp @@ -15,6 +15,15 @@ // // Static library used in testing and executables // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_static { name: "libserviceutils", diff --git a/services/utils/tests/Android.bp b/services/utils/tests/Android.bp index f21254cd7d..54cf5b7404 100644 --- a/services/utils/tests/Android.bp +++ b/services/utils/tests/Android.bp @@ -14,6 +14,15 @@ // Build unit tests. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "prioritydumper_test", test_suites: ["device-tests"], diff --git a/services/vibratorservice/Android.bp b/services/vibratorservice/Android.bp index 4f893539c3..2002bdf628 100644 --- a/services/vibratorservice/Android.bp +++ b/services/vibratorservice/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_shared { name: "libvibratorservice", diff --git a/services/vibratorservice/benchmarks/Android.bp b/services/vibratorservice/benchmarks/Android.bp index 7b4cc199ba..a468146bc0 100644 --- a/services/vibratorservice/benchmarks/Android.bp +++ b/services/vibratorservice/benchmarks/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_benchmark { name: "libvibratorservice_benchmarks", srcs: [ diff --git a/services/vibratorservice/test/Android.bp b/services/vibratorservice/test/Android.bp index ad85990c05..32947246d8 100644 --- a/services/vibratorservice/test/Android.bp +++ b/services/vibratorservice/test/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_test { name: "libvibratorservice_test", test_suites: ["device-tests"], diff --git a/services/vr/Android.bp b/services/vr/Android.bp index 80df479e8d..980dcf4616 100644 --- a/services/vr/Android.bp +++ b/services/vr/Android.bp @@ -1,3 +1,13 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + // SPDX-license-identifier-MIT + default_applicable_licenses: ["frameworks_native_license"], +} + subdirs = [ "*", ] diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp index 7097e7a8cc..f5491cfada 100644 --- a/services/vr/bufferhubd/Android.bp +++ b/services/vr/bufferhubd/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + sharedLibraries = [ "libbase", "libcutils", diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp index 372873149d..866007e188 100644 --- a/services/vr/hardware_composer/Android.bp +++ b/services/vr/hardware_composer/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_shared { name: "libvr_hwc-hal", diff --git a/services/vr/hardware_composer/aidl/Android.bp b/services/vr/hardware_composer/aidl/Android.bp index a1d5392071..fa71ed7633 100644 --- a/services/vr/hardware_composer/aidl/Android.bp +++ b/services/vr/hardware_composer/aidl/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_static { name: "libvr_hwc-binder", srcs: [ diff --git a/services/vr/performanced/Android.bp b/services/vr/performanced/Android.bp index 0ef8cc4762..5eca88b1f9 100644 --- a/services/vr/performanced/Android.bp +++ b/services/vr/performanced/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-MIT + default_applicable_licenses: ["frameworks_native_license"], +} + cc_defaults { name: "performanced_defaults", static_libs: [ diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp index 9cf4905b68..f2ec5a42b1 100644 --- a/services/vr/virtual_touchpad/Android.bp +++ b/services/vr/virtual_touchpad/Android.bp @@ -2,6 +2,15 @@ // Touchpad implementation. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + src = [ "EvdevInjector.cpp", "VirtualTouchpadEvdev.cpp", diff --git a/vulkan/Android.bp b/vulkan/Android.bp index 4934970aaa..33599ea35b 100644 --- a/vulkan/Android.bp +++ b/vulkan/Android.bp @@ -14,6 +14,16 @@ // This module makes the Vulkan libhardware HAL headers available, for // the loader and for HAL/driver implementations. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + // SPDX-license-identifier-MIT + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_headers { name: "hwvulkan_headers", vendor_available: true, diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp index 1d29bab355..67cd8754a3 100644 --- a/vulkan/libvulkan/Android.bp +++ b/vulkan/libvulkan/Android.bp @@ -13,6 +13,15 @@ // limitations under the License. // Headers module is in external/vulkan-headers/Android.bp. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + ndk_library { name: "libvulkan", symbol_file: "libvulkan.map.txt", diff --git a/vulkan/nulldrv/Android.bp b/vulkan/nulldrv/Android.bp index ba025046fa..0daad9c634 100644 --- a/vulkan/nulldrv/Android.bp +++ b/vulkan/nulldrv/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_shared { // Real drivers would set this to vulkan.$(TARGET_BOARD_PLATFORM) name: "vulkan.default", diff --git a/vulkan/vkjson/Android.bp b/vulkan/vkjson/Android.bp index 8528898f3d..fa0258bc06 100644 --- a/vulkan/vkjson/Android.bp +++ b/vulkan/vkjson/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + cc_library_shared { name: "libvkjson", srcs: [ -- cgit v1.2.3-59-g8ed1b From 5b6c96fb85ab6b3280eb3d5efac313f69ff54696 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Thu, 25 Feb 2021 00:21:51 -1000 Subject: Add key event label to Entry dump When examining bugreports, it is inconvenient to have to look up keycodes at the KeyEvent.java file or online in the documentation. When checking the recent queue, it's nice to just have a printed value of a specific key event. Add KeyEvent::getLabel to the entry dump for KeyEntry. Bug: 181096406 Test: press volume keys and then `adb shell dumpsys input` Observe: RecentQueue: length=10 FocusEvent(hasFocus=false), age=14108ms FocusEvent(hasFocus=true), age=14099ms FocusEvent(hasFocus=false), age=14079ms FocusEvent(hasFocus=true), age=11936ms KeyEvent(deviceId=3, eventTime=477682467000, source=0x00000101, displayId=-1, action=DOWN, flags=0x00000008, keyCode=VOLUME_DOWN(25), scanCode=114, metaState=0x00000000, repeatCount=0), policyFlags=0x62000000, age=4160ms KeyEvent(deviceId=3, eventTime=477826780000, source=0x00000101, displayId=-1, action=UP, flags=0x00000008, keyCode=VOLUME_DOWN(25), scanCode=114, metaState=0x00000000, repeatCount=0), policyFlags=0x62000000, age=4015ms KeyEvent(deviceId=3, eventTime=479897187000, source=0x00000101, displayId=-1, action=DOWN, flags=0x00000008, keyCode=VOLUME_DOWN(25), scanCode=114, metaState=0x00000000, repeatCount=0), policyFlags=0x62000000, age=1945ms KeyEvent(deviceId=3, eventTime=480050313000, source=0x00000101, displayId=-1, action=UP, flags=0x00000008, keyCode=VOLUME_DOWN(25), scanCode=114, metaState=0x00000000, repeatCount=0), policyFlags=0x62000000, age=1792ms KeyEvent(deviceId=2, eventTime=480483397000, source=0x00000101, displayId=-1, action=DOWN, flags=0x00000008, keyCode=VOLUME_UP(24), scanCode=115, metaState=0x00000000, repeatCount=0), policyFlags=0x62000000, age=1359ms KeyEvent(deviceId=2, eventTime=480646721000, source=0x00000101, displayId=-1, action=UP, flags=0x00000008, keyCode=VOLUME_UP(24), scanCode=115, metaState=0x00000000, repeatCount=0), policyFlags=0x62000000, age=1195ms Change-Id: Ifeb70526c589508220cade800bd104344dc312ab --- services/inputflinger/dispatcher/Entry.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index a19b04f20e..e45269ed51 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -159,10 +159,11 @@ std::string KeyEntry::getDescription() const { } return StringPrintf("KeyEvent(deviceId=%d, eventTime=%" PRIu64 ", source=0x%08x, displayId=%" PRId32 ", action=%s, " - "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, " + "flags=0x%08x, keyCode=%s(%d), scanCode=%d, metaState=0x%08x, " "repeatCount=%d), policyFlags=0x%08x", deviceId, eventTime, source, displayId, KeyEvent::actionToString(action), - flags, keyCode, scanCode, metaState, repeatCount, policyFlags); + flags, KeyEvent::getLabel(keyCode), keyCode, scanCode, metaState, + repeatCount, policyFlags); } void KeyEntry::recycle() { -- cgit v1.2.3-59-g8ed1b From d0729e1ec2498d3c1dd780063085d352f3436423 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 5 Dec 2018 16:46:06 -0800 Subject: Remove unused function The function is unused. Remove it. Bug: none Test: presubmit only Change-Id: If5af47bbdb119b106021ea79da0bd4b06ea27548 --- include/input/Input.h | 2 -- libs/input/Input.cpp | 4 ---- 2 files changed, 6 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index aa42db8ea8..a8c386e47e 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -328,8 +328,6 @@ struct PointerCoords { float getAxisValue(int32_t axis) const; status_t setAxisValue(int32_t axis, float value); - void scale(float globalScale); - // Scale the pointer coordinates according to a global scale and a // window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR // axes, however the window scaling will not. diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 0a00d68556..8a517c1e9b 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -250,10 +250,6 @@ void PointerCoords::scale(float globalScaleFactor, float windowXScale, float win scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, globalScaleFactor); } -void PointerCoords::scale(float globalScaleFactor) { - scale(globalScaleFactor, globalScaleFactor, globalScaleFactor); -} - void PointerCoords::applyOffset(float xOffset, float yOffset) { setAxisValue(AMOTION_EVENT_AXIS_X, getX() + xOffset); setAxisValue(AMOTION_EVENT_AXIS_Y, getY() + yOffset); -- cgit v1.2.3-59-g8ed1b From 422326f3a31de2b41498f0fe9831a772c0b8bc4b Mon Sep 17 00:00:00 2001 From: Tim Van Patten Date: Tue, 2 Mar 2021 19:24:29 -0700 Subject: Read ro.hardware.egl for ANGLE's filename The ANGLE shared object filename is currently hardcoded to libGLESv2_angle.so, which prevents OEMs from specifying their own filename when using ANGLE as the default OpenGL ES driver. This CL updates initializeAnglePlatform() to build the ANGLE library filename using the suffix specified by ro.hardware.egl when loading ANGLE as the default OpenGL ES driver. The filename when loading ANGLE from an APK will remain libGLESv2_angle.so, for compatibilty reasons. This enforces naming conventions when loading ANGLE APKs on to the device, regardless of the name of the built-in version of ANGLE. Bug: 178871212 Test: Build and launch CF Change-Id: I462e076fc500d84fa2a27abfa491f82db4a9df80 (cherry picked from commit 0222871bc87d9e844315d8a40df4a84f36665ca2) --- opengl/libs/EGL/egl_angle_platform.cpp | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/opengl/libs/EGL/egl_angle_platform.cpp b/opengl/libs/EGL/egl_angle_platform.cpp index c29181d715..d38f2eff01 100644 --- a/opengl/libs/EGL/egl_angle_platform.cpp +++ b/opengl/libs/EGL/egl_angle_platform.cpp @@ -22,6 +22,8 @@ #pragma GCC diagnostic ignored "-Wunused-parameter" #include #pragma GCC diagnostic pop + +#include #include #include #include @@ -33,7 +35,6 @@ namespace angle { -constexpr char kAngleEs2Lib[] = "libGLESv2_angle.so"; constexpr int kAngleDlFlags = RTLD_LOCAL | RTLD_NOW; static GetDisplayPlatformFunc angleGetDisplayPlatform = nullptr; @@ -107,18 +108,36 @@ bool initializeAnglePlatform(EGLDisplay dpy) { android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace(); void* so = nullptr; if (ns) { + // Loading from an APK, so hard-code the suffix to "_angle". + constexpr char kAngleEs2Lib[] = "libGLESv2_angle.so"; const android_dlextinfo dlextinfo = { .flags = ANDROID_DLEXT_USE_NAMESPACE, .library_namespace = ns, }; so = android_dlopen_ext(kAngleEs2Lib, kAngleDlFlags, &dlextinfo); + if (so) { + ALOGD("dlopen_ext from APK (%s) success at %p", kAngleEs2Lib, so); + } else { + ALOGE("dlopen_ext(\"%s\") failed: %s", kAngleEs2Lib, dlerror()); + return false; + } } else { // If we are here, ANGLE is loaded as built-in gl driver in the sphal. - so = android_load_sphal_library(kAngleEs2Lib, kAngleDlFlags); - } - if (!so) { - ALOGE("%s failed to dlopen %s!", __FUNCTION__, kAngleEs2Lib); - return false; + // Get the specified ANGLE library filename suffix. + std::string angleEs2LibSuffix = android::base::GetProperty("ro.hardware.egl", ""); + if (angleEs2LibSuffix.empty()) { + ALOGE("%s failed to get valid ANGLE library filename suffix!", __FUNCTION__); + return false; + } + + std::string angleEs2LibName = "libGLESv2_" + angleEs2LibSuffix + ".so"; + so = android_load_sphal_library(angleEs2LibName.c_str(), kAngleDlFlags); + if (so) { + ALOGD("dlopen (%s) success at %p", angleEs2LibName.c_str(), so); + } else { + ALOGE("%s failed to dlopen %s!", __FUNCTION__, angleEs2LibName.c_str()); + return false; + } } angleGetDisplayPlatform = -- cgit v1.2.3-59-g8ed1b From 4bc7cdf68bdd9d3248e802e3f2f430d05879744f Mon Sep 17 00:00:00 2001 From: Kriti Dang Date: Fri, 8 Jan 2021 11:49:56 +0100 Subject: Hdr format settings [Backend] Added new API to SurfaceControl to override the HDR formats supported by device in SurfaceFlinger. This API is used in the CTS Tests to verify HDR capabilities and enabling/disabling of HDR formats. Bug: 172905874 Test: atest CtsDisplayTestCases Change-Id: Icb13cdd638d315c0e23ece8aa61242470404a428 --- libs/gui/ISurfaceComposer.cpp | 34 ++++++++++++++++++++++++++++ libs/gui/SurfaceComposerClient.cpp | 5 ++++ libs/gui/include/gui/ISurfaceComposer.h | 8 +++++++ libs/gui/include/gui/SurfaceComposerClient.h | 3 +++ libs/gui/tests/Surface_test.cpp | 4 ++++ services/surfaceflinger/DisplayDevice.cpp | 16 +++++++++++-- services/surfaceflinger/DisplayDevice.h | 6 ++++- services/surfaceflinger/SurfaceFlinger.cpp | 24 +++++++++++++++++--- services/surfaceflinger/SurfaceFlinger.h | 2 ++ 9 files changed, 96 insertions(+), 6 deletions(-) diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index bb8124b65e..defa1935b9 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -476,6 +476,26 @@ public: return reply.readInt32(); } + virtual status_t overrideHdrTypes(const sp& display, + const std::vector& hdrTypes) { + Parcel data, reply; + SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); + SAFE_PARCEL(data.writeStrongBinder, display); + + std::vector hdrTypesVector; + for (ui::Hdr i : hdrTypes) { + hdrTypesVector.push_back(static_cast(i)); + } + SAFE_PARCEL(data.writeInt32Vector, hdrTypesVector); + + status_t result = remote()->transact(BnSurfaceComposer::OVERRIDE_HDR_TYPES, data, &reply); + if (result != NO_ERROR) { + ALOGE("overrideHdrTypes failed to transact: %d", result); + return result; + } + return result; + } + status_t enableVSyncInjections(bool enable) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -1962,6 +1982,20 @@ status_t BnSurfaceComposer::onTransact( SAFE_PARCEL(reply->writeInt32, extraBuffers); return NO_ERROR; } + case OVERRIDE_HDR_TYPES: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp display = nullptr; + SAFE_PARCEL(data.readStrongBinder, &display); + + std::vector hdrTypes; + SAFE_PARCEL(data.readInt32Vector, &hdrTypes); + + std::vector hdrTypesVector; + for (int i : hdrTypes) { + hdrTypesVector.push_back(static_cast(i)); + } + return overrideHdrTypes(display, hdrTypesVector); + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index c16a98f42f..229ed7b5c5 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1925,6 +1925,11 @@ status_t SurfaceComposerClient::getAnimationFrameStats(FrameStats* outStats) { return ComposerService::getComposerService()->getAnimationFrameStats(outStats); } +status_t SurfaceComposerClient::overrideHdrTypes(const sp& display, + const std::vector& hdrTypes) { + return ComposerService::getComposerService()->overrideHdrTypes(display, hdrTypes); +} + status_t SurfaceComposerClient::getDisplayedContentSamplingAttributes(const sp& display, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 2a9e3f7923..7cac83bf1c 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -270,6 +270,13 @@ public: */ virtual status_t getAnimationFrameStats(FrameStats* outStats) const = 0; + /* Overrides the supported HDR modes for the given display device. + * + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + virtual status_t overrideHdrTypes(const sp& display, + const std::vector& hdrTypes) = 0; + virtual status_t enableVSyncInjections(bool enable) = 0; virtual status_t injectVSync(nsecs_t when) = 0; @@ -573,6 +580,7 @@ public: GET_DYNAMIC_DISPLAY_INFO, ADD_FPS_LISTENER, REMOVE_FPS_LISTENER, + OVERRIDE_HDR_TYPES, // Always append new enum to the end. }; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 88484c0bbf..55ad09b2bc 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -571,6 +571,9 @@ public: static status_t clearAnimationFrameStats(); static status_t getAnimationFrameStats(FrameStats* outStats); + static status_t overrideHdrTypes(const sp& display, + const std::vector& hdrTypes); + static void setDisplayProjection(const sp& token, ui::Rotation orientation, const Rect& layerStackRect, const Rect& displayRect); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 8d7f8c97f4..5ac3f19486 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -772,6 +772,10 @@ public: status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override { return NO_ERROR; } + status_t overrideHdrTypes(const sp& /*display*/, + const std::vector& /*hdrTypes*/) override { + return NO_ERROR; + } status_t enableVSyncInjections(bool /*enable*/) override { return NO_ERROR; } diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index f4a2a3f03a..b7b2cc691b 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -354,8 +354,20 @@ int DisplayDevice::getSupportedPerFrameMetadata() const { return mCompositionDisplay->getDisplayColorProfile()->getSupportedPerFrameMetadata(); } -const HdrCapabilities& DisplayDevice::getHdrCapabilities() const { - return mCompositionDisplay->getDisplayColorProfile()->getHdrCapabilities(); +void DisplayDevice::overrideHdrTypes(const std::vector& hdrTypes) { + mOverrideHdrTypes = hdrTypes; +} + +HdrCapabilities DisplayDevice::getHdrCapabilities() const { + const HdrCapabilities& capabilities = + mCompositionDisplay->getDisplayColorProfile()->getHdrCapabilities(); + std::vector hdrTypes = capabilities.getSupportedHdrTypes(); + if (!mOverrideHdrTypes.empty()) { + hdrTypes = mOverrideHdrTypes; + } + return HdrCapabilities(hdrTypes, capabilities.getDesiredMaxLuminance(), + capabilities.getDesiredMaxAverageLuminance(), + capabilities.getDesiredMinLuminance()); } std::atomic DisplayDeviceState::sNextSequenceId(1); diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 7156613631..68846d35bd 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -126,13 +126,15 @@ public: bool hasHLGSupport() const; bool hasDolbyVisionSupport() const; + void overrideHdrTypes(const std::vector& hdrTypes); + // The returned HdrCapabilities is the combination of HDR capabilities from // hardware composer and RenderEngine. When the DisplayDevice supports wide // color gamut, RenderEngine is able to simulate HDR support in Display P3 // color space for both PQ and HLG HDR contents. The minimum and maximum // luminance will be set to sDefaultMinLumiance and sDefaultMaxLumiance // respectively if hardware composer doesn't return meaningful values. - const HdrCapabilities& getHdrCapabilities() const; + HdrCapabilities getHdrCapabilities() const; // Return true if intent is supported by the display. bool hasRenderIntent(ui::RenderIntent intent) const; @@ -217,6 +219,8 @@ private: const bool mIsPrimary; std::optional mDeviceProductInfo; + + std::vector mOverrideHdrTypes; }; struct DisplayDeviceState { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d048380dd2..67ba604537 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1291,6 +1291,21 @@ status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const { return NO_ERROR; } +status_t SurfaceFlinger::overrideHdrTypes(const sp& displayToken, + const std::vector& hdrTypes) { + Mutex::Autolock lock(mStateLock); + + auto display = getDisplayDeviceLocked(displayToken); + if (!display) { + ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); + return NAME_NOT_FOUND; + } + + display->overrideHdrTypes(hdrTypes); + dispatchDisplayHotplugEvent(display->getPhysicalId(), true /* connected */); + return NO_ERROR; +} + status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp& displayToken, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, @@ -5004,6 +5019,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case DESTROY_DISPLAY: case ENABLE_VSYNC_INJECTIONS: case GET_ANIMATION_FRAME_STATS: + case OVERRIDE_HDR_TYPES: case GET_HDR_CAPABILITIES: case SET_DESIRED_DISPLAY_MODE_SPECS: case GET_DESIRED_DISPLAY_MODE_SPECS: @@ -5020,9 +5036,11 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case NOTIFY_POWER_BOOST: case SET_GLOBAL_SHADOW_SETTINGS: case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: { - // ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN is used by CTS tests, which acquire the - // necessary permission dynamically. Don't use the permission cache for this check. - bool usePermissionCache = code != ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN; + // ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN and OVERRIDE_HDR_TYPES are used by CTS tests, + // which acquire the necessary permission dynamically. Don't use the permission cache + // for this check. + bool usePermissionCache = + code != ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN && code != OVERRIDE_HDR_TYPES; if (!callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) { IPCThreadState* ipc = IPCThreadState::self(); ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a5b06dfbd4..5464cc3f9b 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -642,6 +642,8 @@ private: void setPowerMode(const sp& displayToken, int mode) override; status_t clearAnimationFrameStats() override; status_t getAnimationFrameStats(FrameStats* outStats) const override; + status_t overrideHdrTypes(const sp& displayToken, + const std::vector& hdrTypes) override; status_t enableVSyncInjections(bool enable) override; status_t injectVSync(nsecs_t when) override; status_t getLayerDebugInfo(std::vector* outLayers) override; -- cgit v1.2.3-59-g8ed1b From 6d043c5c5c1d544c0ecf07cfc07e374e50243050 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Tue, 9 Mar 2021 16:15:10 -0800 Subject: ui: Revamp Size Enable constexpr construction, and touch up style for C++17. Bug: 182939859 Test: Size_test Change-Id: If45175ff18f27414dba9c20d677cd54aaed9cf06 --- libs/ui/Android.bp | 1 - libs/ui/Size.cpp | 24 --- libs/ui/include/ui/Size.h | 183 +++++++++------------ libs/ui/tests/Size_test.cpp | 10 +- .../compositionengine/DisplayCreationArgs.h | 2 +- 5 files changed, 85 insertions(+), 135 deletions(-) delete mode 100644 libs/ui/Size.cpp diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 74d17ced74..5a118eccd3 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -137,7 +137,6 @@ cc_library_shared { "HdrCapabilities.cpp", "PixelFormat.cpp", "PublicFormat.cpp", - "Size.cpp", "StaticDisplayInfo.cpp", ], diff --git a/libs/ui/Size.cpp b/libs/ui/Size.cpp deleted file mode 100644 index d2996d164d..0000000000 --- a/libs/ui/Size.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2019 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 - -namespace android::ui { - -const Size Size::INVALID{-1, -1}; -const Size Size::EMPTY{0, 0}; - -} // namespace android::ui diff --git a/libs/ui/include/ui/Size.h b/libs/ui/include/ui/Size.h index f1e825286e..ecc192dcae 100644 --- a/libs/ui/include/ui/Size.h +++ b/libs/ui/include/ui/Size.h @@ -23,103 +23,70 @@ #include #include -namespace android { -namespace ui { +namespace android::ui { -// Forward declare a few things. -struct Size; -bool operator==(const Size& lhs, const Size& rhs); - -/** - * A simple value type representing a two-dimensional size - */ +// A simple value type representing a two-dimensional size. struct Size { - int32_t width; - int32_t height; + int32_t width = -1; + int32_t height = -1; - // Special values - static const Size INVALID; - static const Size EMPTY; + constexpr Size() = default; - // ------------------------------------------------------------------------ - // Construction - // ------------------------------------------------------------------------ - - Size() : Size(INVALID) {} template - Size(T&& w, T&& h) - : width(Size::clamp(std::forward(w))), - height(Size::clamp(std::forward(h))) {} - - // ------------------------------------------------------------------------ - // Accessors - // ------------------------------------------------------------------------ + constexpr Size(T w, T h) : width(clamp(w)), height(clamp(h)) {} int32_t getWidth() const { return width; } int32_t getHeight() const { return height; } + // Valid means non-negative width and height + bool isValid() const { return width >= 0 && height >= 0; } + + // Empty means zero width and height + bool isEmpty() const; + template - void setWidth(T&& v) { - width = Size::clamp(std::forward(v)); + void setWidth(T v) { + width = clamp(v); } + template - void setHeight(T&& v) { - height = Size::clamp(std::forward(v)); + void setHeight(T v) { + height = clamp(v); } - // ------------------------------------------------------------------------ - // Assignment - // ------------------------------------------------------------------------ + void set(Size size) { *this = size; } - void set(const Size& size) { *this = size; } template - void set(T&& w, T&& h) { - set(Size(std::forward(w), std::forward(h))); + void set(T w, T h) { + set(Size(w, h)); } - // Sets the value to INVALID - void makeInvalid() { set(INVALID); } + // Sets the value to kInvalidSize + void makeInvalid(); - // Sets the value to EMPTY - void clear() { set(EMPTY); } + // Sets the value to kEmptySize + void clear(); - // ------------------------------------------------------------------------ - // Semantic checks - // ------------------------------------------------------------------------ - - // Valid means non-negative width and height - bool isValid() const { return width >= 0 && height >= 0; } - - // Empty means zero width and height - bool isEmpty() const { return *this == EMPTY; } - - // ------------------------------------------------------------------------ - // Clamp Helpers - // ------------------------------------------------------------------------ - - // Note: We use only features available in C++11 here for compatibility with - // external targets which include this file directly or indirectly and which - // themselves use C++11. - - // C++11 compatible replacement for std::remove_cv_reference_t [C++20] + // TODO: Replace with std::remove_cvref_t in C++20. template - using remove_cv_reference_t = - typename std::remove_cv::type>::type; + using remove_cvref_t = std::remove_cv_t>; // Takes a value of type FromType, and ensures it can be represented as a value of type ToType, // clamping the input value to the output range if necessary. template - static Size::remove_cv_reference_t - clamp(typename std::enable_if< - std::numeric_limits>::is_specialized && - std::numeric_limits>::is_specialized, - FromType>::type v) { - using BareToType = remove_cv_reference_t; - using BareFromType = remove_cv_reference_t; - static constexpr auto toHighest = std::numeric_limits::max(); - static constexpr auto toLowest = std::numeric_limits::lowest(); - static constexpr auto fromHighest = std::numeric_limits::max(); - static constexpr auto fromLowest = std::numeric_limits::lowest(); + static constexpr remove_cvref_t clamp(FromType v) { + using BareToType = remove_cvref_t; + using ToLimits = std::numeric_limits; + + using BareFromType = remove_cvref_t; + using FromLimits = std::numeric_limits; + + static_assert(ToLimits::is_specialized && FromLimits::is_specialized); + + constexpr auto toHighest = ToLimits::max(); + constexpr auto toLowest = ToLimits::lowest(); + constexpr auto fromHighest = FromLimits::max(); + constexpr auto fromLowest = FromLimits::lowest(); // Get the closest representation of [toLowest, toHighest] in type // FromType to use to clamp the input value before conversion. @@ -127,37 +94,35 @@ struct Size { // std::common_type<...> is used to get a value-preserving type for the // top end of the range. using CommonHighestType = std::common_type_t; + using CommonLimits = std::numeric_limits; // std::make_signed> is used to get a // value-preserving type for the bottom end of the range, except this is // a bit trickier for non-integer types like float. - using CommonLowestType = - std::conditional_t::is_integer, - std::make_signed_t::is_integer, - CommonHighestType, int /* not used */>>, - CommonHighestType>; + using CommonLowestType = std::conditional_t< + CommonLimits::is_integer, + std::make_signed_t>, + CommonHighestType>; // We can then compute the clamp range in a way that can be later // trivially converted to either the 'from' or 'to' types, and be - // representabile in either. - static constexpr auto commonClampHighest = - std::min(static_cast(fromHighest), - static_cast(toHighest)); - static constexpr auto commonClampLowest = - std::max(static_cast(fromLowest), - static_cast(toLowest)); + // representable in either. + constexpr auto commonClampHighest = std::min(static_cast(fromHighest), + static_cast(toHighest)); + constexpr auto commonClampLowest = std::max(static_cast(fromLowest), + static_cast(toLowest)); - static constexpr auto fromClampHighest = static_cast(commonClampHighest); - static constexpr auto fromClampLowest = static_cast(commonClampLowest); + constexpr auto fromClampHighest = static_cast(commonClampHighest); + constexpr auto fromClampLowest = static_cast(commonClampLowest); // A clamp is needed only if the range we are clamping to is not the // same as the range of the input. - static constexpr bool isClampNeeded = + constexpr bool isClampNeeded = (fromLowest != fromClampLowest) || (fromHighest != fromClampHighest); // If a clamp is not needed, the conversion is just a trivial cast. - if (!isClampNeeded) { + if constexpr (!isClampNeeded) { return static_cast(v); } @@ -170,34 +135,46 @@ struct Size { // Otherwise clamping is done by using the already computed endpoints // for each type. - return (v <= fromClampLowest) - ? toClampLowest - : ((v >= fromClampHighest) ? toClampHighest : static_cast(v)); + if (v <= fromClampLowest) { + return toClampLowest; + } + + return v >= fromClampHighest ? toClampHighest : static_cast(v); } }; -// ------------------------------------------------------------------------ -// Comparisons -// ------------------------------------------------------------------------ +constexpr Size kInvalidSize; +constexpr Size kEmptySize{0, 0}; + +inline void Size::makeInvalid() { + set(kInvalidSize); +} -inline bool operator==(const Size& lhs, const Size& rhs) { +inline void Size::clear() { + set(kEmptySize); +} + +inline bool operator==(Size lhs, Size rhs) { return lhs.width == rhs.width && lhs.height == rhs.height; } -inline bool operator!=(const Size& lhs, const Size& rhs) { - return !operator==(lhs, rhs); +inline bool Size::isEmpty() const { + return *this == kEmptySize; +} + +inline bool operator!=(Size lhs, Size rhs) { + return !(lhs == rhs); } -inline bool operator<(const Size& lhs, const Size& rhs) { +inline bool operator<(Size lhs, Size rhs) { // Orders by increasing width, then height. if (lhs.width != rhs.width) return lhs.width < rhs.width; return lhs.height < rhs.height; } // Defining PrintTo helps with Google Tests. -static inline void PrintTo(const Size& size, ::std::ostream* os) { - *os << "Size(" << size.width << ", " << size.height << ")"; +inline void PrintTo(Size size, std::ostream* stream) { + *stream << "Size(" << size.width << ", " << size.height << ')'; } -} // namespace ui -} // namespace android +} // namespace android::ui diff --git a/libs/ui/tests/Size_test.cpp b/libs/ui/tests/Size_test.cpp index 5f75aeabeb..acef47fb97 100644 --- a/libs/ui/tests/Size_test.cpp +++ b/libs/ui/tests/Size_test.cpp @@ -93,9 +93,8 @@ TEST(SizeTest, ValidAndEmpty) { } { - const auto& s = Size::INVALID; - EXPECT_FALSE(s.isValid()); - EXPECT_FALSE(s.isEmpty()); + EXPECT_FALSE(kInvalidSize.isValid()); + EXPECT_FALSE(kInvalidSize.isEmpty()); } { @@ -112,9 +111,8 @@ TEST(SizeTest, ValidAndEmpty) { } { - const auto& s = Size::EMPTY; - EXPECT_TRUE(s.isValid()); - EXPECT_TRUE(s.isEmpty()); + EXPECT_TRUE(kEmptySize.isValid()); + EXPECT_TRUE(kEmptySize.isEmpty()); } { diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h index 633668e1c2..317d333878 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h @@ -47,7 +47,7 @@ struct DisplayCreationArgs { std::optional physical; // Size of the display in pixels - ui::Size pixels = ui::Size::INVALID; + ui::Size pixels = ui::kInvalidSize; // Pixel format of the display ui::PixelFormat pixelFormat = static_cast(PIXEL_FORMAT_UNKNOWN); -- cgit v1.2.3-59-g8ed1b From 92bf33059cbbe25332b2097e6c43fdee432139cd Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Sat, 3 Apr 2021 19:33:39 +0000 Subject: vkjson: fix VkPhysicalDeviceGroupProperties init Bug: 184267007 Test: adb shell cmd gpu vkjson Change-Id: I8ed3c99b3d2df34294e8e450ca1ec5ce1cee3ac7 --- vulkan/vkjson/vkjson_instance.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc index eb0fcc3443..587249539f 100644 --- a/vulkan/vkjson/vkjson_instance.cc +++ b/vulkan/vkjson/vkjson_instance.cc @@ -363,6 +363,10 @@ VkJsonInstance VkJsonGetInstance() { VkJsonDeviceGroup device_group; std::vector group_properties; group_properties.resize(count); + for (auto& properties : group_properties) { + properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES; + properties.pNext = nullptr; + } result = vkEnumeratePhysicalDeviceGroups(vkinstance, &count, group_properties.data()); if (result != VK_SUCCESS) { -- cgit v1.2.3-59-g8ed1b From 7fed43d17aa7c6d8ff4d7a179d53ee7dc9f26d89 Mon Sep 17 00:00:00 2001 From: gfan Date: Tue, 6 Apr 2021 18:50:06 -0700 Subject: Fix ndk native reference documentation link errors/warnings Trivial changes, no functionality impact. Bug: 183002717 Test: build ndk with 'm ndk' works Change-Id: I1ee646f28500ad5769abdddd4e9780a1915fd528 --- include/android/bitmap.h | 1 + include/android/choreographer.h | 5 +++++ include/android/font.h | 6 +++--- include/android/font_matcher.h | 14 +++++++------- libs/nativewindow/include/android/native_window.h | 5 +++++ 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/include/android/bitmap.h b/include/android/bitmap.h index a70dffd756..6704a1ddf2 100644 --- a/include/android/bitmap.h +++ b/include/android/bitmap.h @@ -241,6 +241,7 @@ typedef struct AHardwareBuffer AHardwareBuffer; * * Available since API level 30. * + * @param env Handle to the JNI environment pointer. * @param bitmap Handle to an android.graphics.Bitmap. * @param outBuffer On success, is set to a pointer to the * {@link AHardwareBuffer} associated with bitmap. This acquires diff --git a/include/android/choreographer.h b/include/android/choreographer.h index cc5420e239..b743f491e4 100644 --- a/include/android/choreographer.h +++ b/include/android/choreographer.h @@ -32,6 +32,11 @@ __BEGIN_DECLS struct AChoreographer; +/** + * Opaque type that provides access to an AChoreographer object. + * + * A pointer can be obtained using {@link AChoreographer_getInstance()}. + */ typedef struct AChoreographer AChoreographer; /** diff --git a/include/android/font.h b/include/android/font.h index a172618829..8a3a474f25 100644 --- a/include/android/font.h +++ b/include/android/font.h @@ -189,7 +189,7 @@ const char* _Nonnull AFont_getFontFilePath(const AFont* _Nonnull font) __INTRODU * Available since API level 29. * * \param font a font object. Passing NULL is not allowed. - * \return a positive integer less than or equal to {@link ASYSTEM_FONT_MAX_WEIGHT} is returned. + * \return a positive integer less than or equal to {@link AFONT_WEIGHT_MAX} is returned. */ uint16_t AFont_getWeight(const AFont* _Nonnull font) __INTRODUCED_IN(29); @@ -241,7 +241,7 @@ size_t AFont_getCollectionIndex(const AFont* _Nonnull font) __INTRODUCED_IN(29); * In this case, AFont_getAxisCount returns 2 and AFont_getAxisTag * and AFont_getAxisValue will return following values. * \code{.cpp} - * AFont* font = AFontIterator_next(ite); + * AFont* font = ASystemFontIterator_next(ite); * * // Returns the number of axes * AFont_getAxisCount(font); // Returns 2 @@ -289,7 +289,7 @@ uint32_t AFont_getAxisTag(const AFont* _Nonnull font, uint32_t axisIndex) * * \param font a font object. Passing NULL is not allowed. * \param axisIndex an index to the font variation settings. Passing value larger than or - * equal to {@link ASYstemFont_getAxisCount} is not allwed. + * equal to {@link AFont_getAxisCount} is not allowed. * \return a float value for the given font variation setting. */ float AFont_getAxisValue(const AFont* _Nonnull font, uint32_t axisIndex) diff --git a/include/android/font_matcher.h b/include/android/font_matcher.h index 49e478c2f3..4417422687 100644 --- a/include/android/font_matcher.h +++ b/include/android/font_matcher.h @@ -36,7 +36,7 @@ * // Simple font query for the ASCII character. * std::vector text = { 'A' }; * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 1 and the font will points a valid font file. * AFontMatcher_destroy(matcher); * @@ -44,17 +44,17 @@ * std::vector text = { 0x9AA8 }; * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); * AFontMatcher_setLocales(matcher, "zh-CN,ja-JP"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 1 and the font will points a Simplified Chinese font. * AFontMatcher_setLocales(matcher, "ja-JP,zh-CN"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 1 and the font will points a Japanese font. * AFontMatcher_destroy(matcher); * * // Querying font for text/color emoji * std::vector text = { 0xD83D, 0xDC68, 0x200D, 0x2764, 0xFE0F, 0x200D, 0xD83D, 0xDC68 }; * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 8 and the font will points a color emoji font. * AFontMatcher_destroy(matcher); * @@ -62,7 +62,7 @@ * // 0x05D0 is a Hebrew character and 0x0E01 is a Thai character. * std::vector text = { 0x05D0, 0x0E01 }; * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 1 and the font will points a Hebrew font. * AFontMatcher_destroy(matcher); * \endcode @@ -146,7 +146,7 @@ void AFontMatcher_destroy(AFontMatcher* _Nonnull matcher) __INTRODUCED_IN(29); /** * Set font style to matcher. * - * If this function is not called, the matcher performs with {@link ASYSTEM_FONT_WEIGHT_NORMAL} + * If this function is not called, the matcher performs with {@link AFONT_WEIGHT_NORMAL} * with non-italic style. * * Available since API level 29. @@ -206,7 +206,7 @@ void AFontMatcher_setFamilyVariant( * \param textLength a length of the given text buffer. This must not be zero. * \param runLengthOut if not null, the font run length will be filled. * \return a font to be used for given text and params. You need to release the returned font by - * ASystemFont_close when it is no longer needed. + * AFont_close when it is no longer needed. */ AFont* _Nonnull AFontMatcher_match( const AFontMatcher* _Nonnull matcher, diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index 50e9d53604..61b3f94aab 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -157,6 +157,7 @@ int32_t ANativeWindow_getFormat(ANativeWindow* window); * For all of these parameters, if 0 is supplied then the window's base * value will come back in force. * + * \param window pointer to an ANativeWindow object. * \param width width of the buffers in pixels. * \param height height of the buffers in pixels. * \param format one of the AHardwareBuffer_Format constants. @@ -191,6 +192,7 @@ int32_t ANativeWindow_unlockAndPost(ANativeWindow* window); * * Available since API level 26. * + * \param window pointer to an ANativeWindow object. * \param transform combination of {@link ANativeWindowTransform} flags * \return 0 for success, or -EINVAL if \p transform is invalid */ @@ -208,6 +210,7 @@ int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transfo * * Available since API level 28. * + * \param window pointer to an ANativeWindow object. * \param dataSpace data space of all buffers queued after this call. * \return 0 for success, -EINVAL if window is invalid or the dataspace is not * supported. @@ -306,6 +309,8 @@ enum ANativeWindow_ChangeFrameRateStrategy { * valid refresh rate for this device's display - e.g., it's fine to pass 30fps * to a device that can only run the display at 60fps. * + * \param window pointer to an ANativeWindow object. + * * \param compatibility The frame rate compatibility of this window. The * compatibility value may influence the system's choice of display refresh * rate. See the ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* values for more info. -- cgit v1.2.3-59-g8ed1b From fe13a4a8860cf544e1d218310b331f535ad96100 Mon Sep 17 00:00:00 2001 From: Brian Osman Date: Tue, 20 Apr 2021 17:46:40 +0000 Subject: Update RenderEngine to use newer SkRuntimeEffect::MakeForShader This enforces stricter rules on the SkSL at effect creation time, and ensures it's valid as an SkShader (vs. an SkColorFilter). Bug: skia:11813 Change-Id: Iddba9361a453fd4adc8ffd8fd41c0b0ab2905fad --- libs/renderengine/skia/filters/BlurFilter.cpp | 6 +++--- libs/renderengine/skia/filters/LinearEffect.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp index 6dd416101d..2028def0e8 100644 --- a/libs/renderengine/skia/filters/BlurFilter.cpp +++ b/libs/renderengine/skia/filters/BlurFilter.cpp @@ -53,7 +53,7 @@ BlurFilter::BlurFilter() { } )"); - auto [blurEffect, error] = SkRuntimeEffect::Make(blurString); + auto [blurEffect, error] = SkRuntimeEffect::MakeForShader(blurString); if (!blurEffect) { LOG_ALWAYS_FATAL("RuntimeShader error: %s", error.c_str()); } @@ -65,11 +65,11 @@ BlurFilter::BlurFilter() { uniform float mixFactor; half4 main(float2 xy) { - return half4(mix(sample(originalInput), sample(blurredInput), mixFactor)); + return half4(mix(sample(originalInput, xy), sample(blurredInput, xy), mixFactor)); } )"); - auto [mixEffect, mixError] = SkRuntimeEffect::Make(mixString); + auto [mixEffect, mixError] = SkRuntimeEffect::MakeForShader(mixString); if (!mixEffect) { LOG_ALWAYS_FATAL("RuntimeShader error: %s", mixError.c_str()); } diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp index 8e8e42e75a..0fbd6698d8 100644 --- a/libs/renderengine/skia/filters/LinearEffect.cpp +++ b/libs/renderengine/skia/filters/LinearEffect.cpp @@ -438,7 +438,7 @@ sk_sp buildRuntimeEffect(const LinearEffect& linearEffect) { generateOETF(linearEffect.outputDataspace, shaderString); generateEffectiveOOTF(linearEffect.undoPremultipliedAlpha, shaderString); - auto [shader, error] = SkRuntimeEffect::Make(shaderString); + auto [shader, error] = SkRuntimeEffect::MakeForShader(shaderString); if (!shader) { LOG_ALWAYS_FATAL("LinearColorFilter construction error: %s", error.c_str()); } -- cgit v1.2.3-59-g8ed1b From 7b9bf4cbd84ce704a90c8933daad96abfe70b0c5 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Thu, 18 Mar 2021 12:21:29 -0700 Subject: SF: Parametrize display lookup The predicate will match not only on layer stack in the next CL. Bug: 182939859 Test: screencap -d Change-Id: I3d30b282fdf2b80faaedd732f4ff6f032c62ca3d --- services/surfaceflinger/DisplayDevice.h | 12 +++++++ services/surfaceflinger/SurfaceFlinger.cpp | 55 +++++++++--------------------- services/surfaceflinger/SurfaceFlinger.h | 26 +++++++++++--- 3 files changed, 51 insertions(+), 42 deletions(-) diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 68846d35bd..9976e1e43c 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -282,4 +282,16 @@ struct DisplayDeviceCreationArgs { DisplayModes supportedModes; }; +// Predicates for display lookup. + +struct WithLayerStack { + explicit WithLayerStack(ui::LayerStack layerStack) : layerStack(layerStack) {} + + bool operator()(const DisplayDevice& display) const { + return display.getLayerStack() == layerStack; + } + + ui::LayerStack layerStack; +}; + } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2da8ed4ab0..548aa3262c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2175,11 +2175,10 @@ void SurfaceFlinger::postComposition() { mFpsReporter->dispatchLayerFps(); } hdrInfoListeners.reserve(mHdrLayerInfoListeners.size()); - for (auto& [key, value] : mHdrLayerInfoListeners) { - if (value && value->hasListeners()) { - auto listenersDisplay = getDisplayById(key); - if (listenersDisplay) { - hdrInfoListeners.emplace_back(listenersDisplay->getCompositionDisplay(), value); + for (const auto& [displayId, reporter] : mHdrLayerInfoListeners) { + if (reporter && reporter->hasListeners()) { + if (const auto display = getDisplayDeviceLocked(displayId)) { + hdrInfoListeners.emplace_back(display->getCompositionDisplay(), reporter); } } } @@ -5708,34 +5707,6 @@ status_t SurfaceFlinger::setSchedFifo(bool enabled) { return NO_ERROR; } -sp SurfaceFlinger::getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) { - if (const sp displayToken = - getPhysicalDisplayTokenLocked(PhysicalDisplayId{displayOrLayerStack})) { - return getDisplayDeviceLocked(displayToken); - } - // Couldn't find display by displayId. Try to get display by layerStack since virtual displays - // may not have a displayId. - return getDisplayByLayerStack(displayOrLayerStack); -} - -sp SurfaceFlinger::getDisplayById(DisplayId displayId) const { - for (const auto& [token, display] : mDisplays) { - if (display->getId() == displayId) { - return display; - } - } - return nullptr; -} - -sp SurfaceFlinger::getDisplayByLayerStack(uint64_t layerStack) { - for (const auto& [token, display] : mDisplays) { - if (display->getLayerStack() == layerStack) { - return display; - } - } - return nullptr; -} - status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, const sp& captureListener) { ATRACE_CALL(); @@ -5747,7 +5718,7 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, if (!args.displayToken) return BAD_VALUE; - wp displayWeak; + wp displayWeak; ui::LayerStack layerStack; ui::Size reqSize(args.width, args.height); ui::Dataspace dataspace; @@ -5788,18 +5759,26 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, captureListener); } -status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack, +status_t SurfaceFlinger::captureDisplay(uint64_t displayIdOrLayerStack, const sp& captureListener) { ui::LayerStack layerStack; - wp displayWeak; + wp displayWeak; ui::Size size; ui::Dataspace dataspace; { Mutex::Autolock lock(mStateLock); - sp display = getDisplayByIdOrLayerStack(displayOrLayerStack); + auto display = getDisplayDeviceLocked(PhysicalDisplayId{displayIdOrLayerStack}); + + // Fall back to first display whose layer stack matches. + if (!display) { + const auto layerStack = static_cast(displayIdOrLayerStack); + display = findDisplay(WithLayerStack(layerStack)); + } + if (!display) { return NAME_NOT_FOUND; } + layerStack = display->getLayerStack(); displayWeak = display; @@ -5884,7 +5863,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, } } - const auto display = getDisplayByLayerStack(parent->getLayerStack()); + const auto display = findDisplay(WithLayerStack(parent->getLayerStack())); if (!display) { return NAME_NOT_FOUND; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index cf1a545342..fb82b3ee9e 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -907,10 +907,6 @@ private: bool forSystem, bool regionSampling, bool grayscale, ScreenCaptureResults&); - sp getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock); - sp getDisplayById(DisplayId displayId) const REQUIRES(mStateLock); - sp getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock); - // If the uid provided is not UNSET_UID, the traverse will skip any layers that don't have a // matching ownerUid void traverseLayersInLayerStack(ui::LayerStack, const int32_t uid, const LayerVector::Visitor&); @@ -936,6 +932,14 @@ private: return it == mDisplays.end() ? nullptr : it->second; } + sp getDisplayDeviceLocked(PhysicalDisplayId id) const + REQUIRES(mStateLock) { + if (const auto token = getPhysicalDisplayTokenLocked(id)) { + return getDisplayDeviceLocked(token); + } + return nullptr; + } + sp getDefaultDisplayDeviceLocked() const REQUIRES(mStateLock) { return const_cast(this)->getDefaultDisplayDeviceLocked(); } @@ -952,6 +956,20 @@ private: return getDefaultDisplayDeviceLocked(); } + // Returns the first display that matches a `bool(const DisplayDevice&)` predicate. + template + sp findDisplay(Predicate p) const REQUIRES(mStateLock) { + const auto it = std::find_if(mDisplays.begin(), mDisplays.end(), + [&](const auto& pair) { return p(*pair.second); }); + + return it == mDisplays.end() ? nullptr : it->second; + } + + sp getDisplayDeviceLocked(DisplayId id) const REQUIRES(mStateLock) { + // TODO(b/182939859): Replace tokens with IDs for display lookup. + return findDisplay([id](const auto& display) { return display.getId() == id; }); + } + // mark a region of a layer stack dirty. this updates the dirty // region of all screens presenting this layer stack. void invalidateLayerStack(const sp& layer, const Region& dirty); -- cgit v1.2.3-59-g8ed1b From f1833853ccc1a54dcc7056a9f87eefa1baccc945 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Tue, 23 Mar 2021 15:06:50 -0700 Subject: SF: Remove layer stack lookup for screencap GPU virtual displays now have IDs, so the (ambiguous) fallback is no longer necessary. Remove PhysicalDisplayId constructor from uint64_t to enforce error checking at compile time when upcasting or deserializing. Bug: 162612135 Bug: 182939859 Test: screencap -d Test: DisplayId_test Change-Id: I68fa0835cbc915975c7fa40c7d544d9491db9fa2 --- libs/gui/ISurfaceComposer.cpp | 30 +++++++---- libs/gui/SurfaceComposerClient.cpp | 4 +- libs/gui/include/gui/ISurfaceComposer.h | 20 ++++---- libs/gui/include/gui/SurfaceComposerClient.h | 9 ++-- libs/gui/tests/Surface_test.cpp | 16 +++--- libs/nativedisplay/AChoreographer.cpp | 5 +- libs/ui/include/ui/DisplayId.h | 35 ++++++++++--- libs/ui/tests/DisplayId_test.cpp | 12 +++++ .../display/AutomotiveDisplayProxyService.cpp | 11 +++- .../CompositionEngine/tests/DisplayTest.cpp | 7 +-- .../CompositionEngine/tests/RenderSurfaceTest.cpp | 4 +- services/surfaceflinger/DisplayDevice.h | 12 ----- services/surfaceflinger/SurfaceFlinger.cpp | 58 ++++++++-------------- services/surfaceflinger/SurfaceFlinger.h | 18 ++----- .../tests/fakehwc/SFFakeHwc_test.cpp | 4 +- .../tests/unittests/CompositionTest.cpp | 2 +- .../tests/unittests/DisplayTransactionTest.cpp | 2 +- .../tests/unittests/EventThreadTest.cpp | 9 ++-- .../tests/unittests/SchedulerTest.cpp | 2 +- 19 files changed, 133 insertions(+), 127 deletions(-) diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 53721cf6f7..0436758e72 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -123,11 +123,11 @@ public: return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY, data, &reply); } - status_t captureDisplay(uint64_t displayOrLayerStack, + status_t captureDisplay(DisplayId displayId, const sp& captureListener) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeUint64, displayOrLayerStack); + SAFE_PARCEL(data.writeUint64, displayId.value); SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(captureListener)); return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID, data, &reply); @@ -281,9 +281,14 @@ public: NO_ERROR) { std::vector rawIds; if (reply.readUint64Vector(&rawIds) == NO_ERROR) { - std::vector displayIds(rawIds.size()); - std::transform(rawIds.begin(), rawIds.end(), displayIds.begin(), - [](uint64_t rawId) { return PhysicalDisplayId(rawId); }); + std::vector displayIds; + displayIds.reserve(rawIds.size()); + + for (const uint64_t rawId : rawIds) { + if (const auto id = DisplayId::fromValue(rawId)) { + displayIds.push_back(*id); + } + } return displayIds; } } @@ -1296,12 +1301,15 @@ status_t BnSurfaceComposer::onTransact( } case CAPTURE_DISPLAY_BY_ID: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - uint64_t displayOrLayerStack = 0; + uint64_t value; + SAFE_PARCEL(data.readUint64, &value); + const auto id = DisplayId::fromValue(value); + if (!id) return BAD_VALUE; + sp captureListener; - SAFE_PARCEL(data.readUint64, &displayOrLayerStack); SAFE_PARCEL(data.readStrongBinder, &captureListener); - return captureDisplay(displayOrLayerStack, captureListener); + return captureDisplay(*id, captureListener); } case CAPTURE_LAYERS: { CHECK_INTERFACE(ISurfaceComposer, data, reply); @@ -1368,9 +1376,9 @@ status_t BnSurfaceComposer::onTransact( } case GET_PHYSICAL_DISPLAY_TOKEN: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - PhysicalDisplayId displayId(data.readUint64()); - sp display = getPhysicalDisplayToken(displayId); - reply->writeStrongBinder(display); + const auto id = DisplayId::fromValue(data.readUint64()); + if (!id) return BAD_VALUE; + reply->writeStrongBinder(getPhysicalDisplayToken(*id)); return NO_ERROR; } case GET_DISPLAY_STATE: { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 83124cf0cd..fd72a00339 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2098,12 +2098,12 @@ status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs, return s->captureDisplay(captureArgs, captureListener); } -status_t ScreenshotClient::captureDisplay(uint64_t displayOrLayerStack, +status_t ScreenshotClient::captureDisplay(DisplayId displayId, const sp& captureListener) { sp s(ComposerService::getComposerService()); if (s == nullptr) return NO_INIT; - return s->captureDisplay(displayOrLayerStack, captureListener); + return s->captureDisplay(displayId, captureListener); } status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs, diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index cb0468901a..c420e4a8d4 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -114,6 +114,11 @@ public: using EventRegistrationFlags = Flags; + template + struct SpHash { + size_t operator()(const sp& k) const { return std::hash()(k.get()); } + }; + /* * Create a connection with SurfaceFlinger. */ @@ -237,24 +242,17 @@ public: * The subregion can be optionally rotated. It will also be scaled to * match the size of the output buffer. */ - virtual status_t captureDisplay(const DisplayCaptureArgs& args, - const sp& captureListener) = 0; + virtual status_t captureDisplay(const DisplayCaptureArgs&, + const sp&) = 0; - virtual status_t captureDisplay(uint64_t displayOrLayerStack, - const sp& captureListener) = 0; - - template - struct SpHash { - size_t operator()(const sp& k) const { return std::hash()(k.get()); } - }; + virtual status_t captureDisplay(DisplayId, const sp&) = 0; /** * Capture a subtree of the layer hierarchy, potentially ignoring the root node. * This requires READ_FRAME_BUFFER permission. This function will fail if there * is a secure window on screen */ - virtual status_t captureLayers(const LayerCaptureArgs& args, - const sp& captureListener) = 0; + virtual status_t captureLayers(const LayerCaptureArgs&, const sp&) = 0; /* Clears the frame statistics for animations. * diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 5bbd8e3d85..da360e2760 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -608,12 +608,9 @@ private: class ScreenshotClient { public: - static status_t captureDisplay(const DisplayCaptureArgs& captureArgs, - const sp& captureListener); - static status_t captureDisplay(uint64_t displayOrLayerStack, - const sp& captureListener); - static status_t captureLayers(const LayerCaptureArgs& captureArgs, - const sp& captureListener); + static status_t captureDisplay(const DisplayCaptureArgs&, const sp&); + static status_t captureDisplay(DisplayId, const sp&); + static status_t captureLayers(const LayerCaptureArgs&, const sp&); }; // --------------------------------------------------------------------------- diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index ea8c2957a1..7002adf1ba 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -752,21 +752,19 @@ public: } status_t setActiveColorMode(const sp& /*display*/, ColorMode /*colorMode*/) override { return NO_ERROR; } - status_t captureDisplay(const DisplayCaptureArgs& /* captureArgs */, - const sp& /* captureListener */) override { - return NO_ERROR; - } void setAutoLowLatencyMode(const sp& /*display*/, bool /*on*/) override {} void setGameContentType(const sp& /*display*/, bool /*on*/) override {} - status_t captureDisplay(uint64_t /*displayOrLayerStack*/, - const sp& /* captureListener */) override { + + status_t captureDisplay(const DisplayCaptureArgs&, const sp&) override { return NO_ERROR; } - virtual status_t captureLayers( - const LayerCaptureArgs& /* captureArgs */, - const sp& /* captureListener */) override { + status_t captureDisplay(DisplayId, const sp&) override { return NO_ERROR; } + status_t captureLayers(const LayerCaptureArgs&, const sp&) override { + return NO_ERROR; + } + status_t clearAnimationFrameStats() override { return NO_ERROR; } status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override { return NO_ERROR; diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index 0edb213089..e7bd977876 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -306,8 +306,9 @@ void Choreographer::scheduleLatestConfigRequest() { // Fortunately, these events are small so sending packets across the // socket should be atomic across processes. DisplayEventReceiver::Event event; - event.header = DisplayEventReceiver::Event::Header{DisplayEventReceiver::DISPLAY_EVENT_NULL, - PhysicalDisplayId(0), systemTime()}; + event.header = + DisplayEventReceiver::Event::Header{DisplayEventReceiver::DISPLAY_EVENT_NULL, + PhysicalDisplayId::fromPort(0), systemTime()}; injectEvent(event); } } diff --git a/libs/ui/include/ui/DisplayId.h b/libs/ui/include/ui/DisplayId.h index f196ab901a..9120972a42 100644 --- a/libs/ui/include/ui/DisplayId.h +++ b/libs/ui/include/ui/DisplayId.h @@ -38,12 +38,22 @@ struct DisplayId { uint64_t value; + // For deserialization. + static constexpr std::optional fromValue(uint64_t); + + // As above, but also upcast to Id. + template + static constexpr std::optional fromValue(uint64_t value) { + if (const auto id = Id::tryCast(DisplayId(value))) { + return id; + } + return {}; + } + protected: explicit constexpr DisplayId(uint64_t id) : value(id) {} }; -static_assert(sizeof(DisplayId) == sizeof(uint64_t)); - inline bool operator==(DisplayId lhs, DisplayId rhs) { return lhs.value == rhs.value; } @@ -80,11 +90,8 @@ struct PhysicalDisplayId : DisplayId { // TODO(b/162612135) Remove default constructor PhysicalDisplayId() = default; - // TODO(b/162612135) Remove constructor - explicit constexpr PhysicalDisplayId(uint64_t id) : DisplayId(id) {} constexpr uint16_t getManufacturerId() const { return static_cast(value >> 40); } - constexpr uint8_t getPort() const { return static_cast(value); } private: @@ -96,10 +103,9 @@ private: explicit constexpr PhysicalDisplayId(DisplayId other) : DisplayId(other) {} }; -static_assert(sizeof(PhysicalDisplayId) == sizeof(uint64_t)); - struct VirtualDisplayId : DisplayId { using BaseId = uint32_t; + // Flag indicating that this virtual display is backed by the GPU. static constexpr uint64_t FLAG_GPU = 1ULL << 61; @@ -163,10 +169,23 @@ private: explicit constexpr HalDisplayId(DisplayId other) : DisplayId(other) {} }; +constexpr std::optional DisplayId::fromValue(uint64_t value) { + if (const auto id = fromValue(value)) { + return id; + } + if (const auto id = fromValue(value)) { + return id; + } + return {}; +} + +static_assert(sizeof(DisplayId) == sizeof(uint64_t)); +static_assert(sizeof(HalDisplayId) == sizeof(uint64_t)); static_assert(sizeof(VirtualDisplayId) == sizeof(uint64_t)); + +static_assert(sizeof(PhysicalDisplayId) == sizeof(uint64_t)); static_assert(sizeof(HalVirtualDisplayId) == sizeof(uint64_t)); static_assert(sizeof(GpuVirtualDisplayId) == sizeof(uint64_t)); -static_assert(sizeof(HalDisplayId) == sizeof(uint64_t)); } // namespace android diff --git a/libs/ui/tests/DisplayId_test.cpp b/libs/ui/tests/DisplayId_test.cpp index 1d908b8ef1..8ddee7e740 100644 --- a/libs/ui/tests/DisplayId_test.cpp +++ b/libs/ui/tests/DisplayId_test.cpp @@ -32,6 +32,9 @@ TEST(DisplayIdTest, createPhysicalIdFromEdid) { EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id)); EXPECT_TRUE(PhysicalDisplayId::tryCast(id)); EXPECT_TRUE(HalDisplayId::tryCast(id)); + + EXPECT_EQ(id, DisplayId::fromValue(id.value)); + EXPECT_EQ(id, DisplayId::fromValue(id.value)); } TEST(DisplayIdTest, createPhysicalIdFromPort) { @@ -43,6 +46,9 @@ TEST(DisplayIdTest, createPhysicalIdFromPort) { EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id)); EXPECT_TRUE(PhysicalDisplayId::tryCast(id)); EXPECT_TRUE(HalDisplayId::tryCast(id)); + + EXPECT_EQ(id, DisplayId::fromValue(id.value)); + EXPECT_EQ(id, DisplayId::fromValue(id.value)); } TEST(DisplayIdTest, createGpuVirtualId) { @@ -52,6 +58,9 @@ TEST(DisplayIdTest, createGpuVirtualId) { EXPECT_FALSE(HalVirtualDisplayId::tryCast(id)); EXPECT_FALSE(PhysicalDisplayId::tryCast(id)); EXPECT_FALSE(HalDisplayId::tryCast(id)); + + EXPECT_EQ(id, DisplayId::fromValue(id.value)); + EXPECT_EQ(id, DisplayId::fromValue(id.value)); } TEST(DisplayIdTest, createHalVirtualId) { @@ -61,6 +70,9 @@ TEST(DisplayIdTest, createHalVirtualId) { EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id)); EXPECT_FALSE(PhysicalDisplayId::tryCast(id)); EXPECT_TRUE(HalDisplayId::tryCast(id)); + + EXPECT_EQ(id, DisplayId::fromValue(id.value)); + EXPECT_EQ(id, DisplayId::fromValue(id.value)); } } // namespace android::ui diff --git a/services/automotive/display/AutomotiveDisplayProxyService.cpp b/services/automotive/display/AutomotiveDisplayProxyService.cpp index d6fc69562b..d205231033 100644 --- a/services/automotive/display/AutomotiveDisplayProxyService.cpp +++ b/services/automotive/display/AutomotiveDisplayProxyService.cpp @@ -34,7 +34,10 @@ AutomotiveDisplayProxyService::getIGraphicBufferProducer(uint64_t id) { sp displayToken = nullptr; sp surfaceControl = nullptr; if (it == mDisplays.end()) { - displayToken = SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId(id)); + if (const auto displayId = DisplayId::fromValue(id)) { + displayToken = SurfaceComposerClient::getPhysicalDisplayToken(*displayId); + } + if (displayToken == nullptr) { ALOGE("Given display id, 0x%lX, is invalid.", (unsigned long)id); return nullptr; @@ -157,7 +160,11 @@ Return AutomotiveDisplayProxyService::getDisplayInfo(uint64_t id, getDispl HwDisplayConfig activeConfig; HwDisplayState activeState; - auto displayToken = SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId(id)); + sp displayToken; + if (const auto displayId = DisplayId::fromValue(id)) { + displayToken = SurfaceComposerClient::getPhysicalDisplayToken(*displayId); + } + if (displayToken == nullptr) { ALOGE("Given display id, 0x%lX, is invalid.", (unsigned long)id); } else { diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 8a83639ce5..b31e64ac0d 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -60,9 +60,10 @@ using testing::Sequence; using testing::SetArgPointee; using testing::StrictMock; -constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId{42}; +constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u); // TODO(b/160679868) Use VirtualDisplayId -constexpr PhysicalDisplayId VIRTUAL_DISPLAY_ID = PhysicalDisplayId{43}; +constexpr PhysicalDisplayId VIRTUAL_DISPLAY_ID = PhysicalDisplayId::fromPort(43u); + constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920; constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080; constexpr int32_t DEFAULT_LAYER_STACK = 123; @@ -1049,4 +1050,4 @@ TEST_F(DisplayFunctionalTest, postFramebufferCriticalCallsAreOrdered) { } // namespace android::compositionengine // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file +#pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index 9aeb290eb5..8579d8c444 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -39,7 +39,7 @@ namespace { constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920; constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080; -constexpr DisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId(123u); +constexpr DisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(123u); const std::string DEFAULT_DISPLAY_NAME = "Mock Display"; using testing::_; @@ -374,4 +374,4 @@ TEST_F(RenderSurfaceTest, flipForwardsSignal) { } // namespace android::compositionengine // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file +#pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 9976e1e43c..68846d35bd 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -282,16 +282,4 @@ struct DisplayDeviceCreationArgs { DisplayModes supportedModes; }; -// Predicates for display lookup. - -struct WithLayerStack { - explicit WithLayerStack(ui::LayerStack layerStack) : layerStack(layerStack) {} - - bool operator()(const DisplayDevice& display) const { - return display.getLayerStack() == layerStack; - } - - ui::LayerStack layerStack; -}; - } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 548aa3262c..eb3ae269eb 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5492,37 +5492,24 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } case 1035: { const int modeId = data.readInt32(); - mDebugDisplayModeSetByBackdoor = false; - - const auto displayId = [&]() -> std::optional { - uint64_t inputDisplayId = 0; - if (data.readUint64(&inputDisplayId) == NO_ERROR) { - const auto token = getPhysicalDisplayToken( - static_cast(inputDisplayId)); - if (!token) { - ALOGE("No display with id: %" PRIu64, inputDisplayId); - return std::nullopt; - } - return std::make_optional(inputDisplayId); + const auto display = [&]() -> sp { + uint64_t value; + if (data.readUint64(&value) != NO_ERROR) { + return getInternalDisplayToken(); } - return getInternalDisplayId(); - }(); - - if (!displayId) { - ALOGE("No display found"); - return NO_ERROR; - } - - status_t result = setActiveMode(getPhysicalDisplayToken(*displayId), modeId); - if (result != NO_ERROR) { - return result; - } + if (const auto id = DisplayId::fromValue(value)) { + return getPhysicalDisplayToken(*id); + } - mDebugDisplayModeSetByBackdoor = true; + ALOGE("Invalid physical display ID"); + return nullptr; + }(); - return NO_ERROR; + const status_t result = setActiveMode(display, modeId); + mDebugDisplayModeSetByBackdoor = result == NO_ERROR; + return result; } case 1036: { if (data.readInt32() > 0) { @@ -5759,7 +5746,7 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, captureListener); } -status_t SurfaceFlinger::captureDisplay(uint64_t displayIdOrLayerStack, +status_t SurfaceFlinger::captureDisplay(DisplayId displayId, const sp& captureListener) { ui::LayerStack layerStack; wp displayWeak; @@ -5767,21 +5754,14 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayIdOrLayerStack, ui::Dataspace dataspace; { Mutex::Autolock lock(mStateLock); - auto display = getDisplayDeviceLocked(PhysicalDisplayId{displayIdOrLayerStack}); - - // Fall back to first display whose layer stack matches. - if (!display) { - const auto layerStack = static_cast(displayIdOrLayerStack); - display = findDisplay(WithLayerStack(layerStack)); - } + const auto display = getDisplayDeviceLocked(displayId); if (!display) { return NAME_NOT_FOUND; } - layerStack = display->getLayerStack(); displayWeak = display; - + layerStack = display->getLayerStack(); size = display->getLayerStackSpaceRect().getSize(); dataspace = @@ -5863,7 +5843,11 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, } } - const auto display = findDisplay(WithLayerStack(parent->getLayerStack())); + const auto display = + findDisplay([layerStack = parent->getLayerStack()](const auto& display) { + return display.getLayerStack() == layerStack; + }); + if (!display) { return NAME_NOT_FOUND; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index fb82b3ee9e..66702fe836 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -613,12 +613,10 @@ private: sp createDisplayEventConnection( ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp, ISurfaceComposer::EventRegistrationFlags eventRegistration = {}) override; - status_t captureDisplay(const DisplayCaptureArgs& args, - const sp& captureListener) override; - status_t captureDisplay(uint64_t displayOrLayerStack, - const sp& captureListener) override; - status_t captureLayers(const LayerCaptureArgs& args, - const sp& captureListener) override; + + status_t captureDisplay(const DisplayCaptureArgs&, const sp&) override; + status_t captureDisplay(DisplayId, const sp&) override; + status_t captureLayers(const LayerCaptureArgs&, const sp&) override; status_t getDisplayStats(const sp& displayToken, DisplayStatInfo* stats) override; status_t getDisplayState(const sp& displayToken, ui::DisplayState*) @@ -932,14 +930,6 @@ private: return it == mDisplays.end() ? nullptr : it->second; } - sp getDisplayDeviceLocked(PhysicalDisplayId id) const - REQUIRES(mStateLock) { - if (const auto token = getPhysicalDisplayTokenLocked(id)) { - return getDisplayDeviceLocked(token); - } - return nullptr; - } - sp getDefaultDisplayDeviceLocked() const REQUIRES(mStateLock) { return const_cast(this)->getDefaultDisplayDeviceLocked(); } diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index 162711d6f5..a9e935df22 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -279,7 +279,7 @@ protected: } bool waitForHotplugEvent(Display displayId, bool connected) { - return waitForHotplugEvent(PhysicalDisplayId(displayId), connected); + return waitForHotplugEvent(physicalIdFromHwcDisplayId(displayId), connected); } bool waitForHotplugEvent(PhysicalDisplayId displayId, bool connected) { @@ -305,7 +305,7 @@ protected: } bool waitForModeChangedEvent(Display display, int32_t modeId) { - PhysicalDisplayId displayId(display); + PhysicalDisplayId displayId = physicalIdFromHwcDisplayId(display); int waitCount = 20; while (waitCount--) { while (!mReceivedDisplayEvents.empty()) { diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 3042450f29..e42cf47657 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -77,7 +77,7 @@ constexpr hal::HWDisplayId HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DIS constexpr hal::HWLayerId HWC_LAYER = 5000; constexpr Transform DEFAULT_TRANSFORM = static_cast(0); -constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID(42); +constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u); constexpr int DEFAULT_DISPLAY_WIDTH = 1920; constexpr int DEFAULT_DISPLAY_HEIGHT = 1024; diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index a3e810871c..359e555e92 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -118,7 +118,7 @@ void DisplayTransactionTest::injectFakeNativeWindowSurfaceFactory() { sp DisplayTransactionTest::injectDefaultInternalDisplay( std::function injectExtra) { - constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID(777); + constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(255u); constexpr int DEFAULT_DISPLAY_WIDTH = 1080; constexpr int DEFAULT_DISPLAY_HEIGHT = 1920; constexpr HWDisplayId DEFAULT_DISPLAY_HWC_DISPLAY_ID = 0; diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index b4a1481e9c..62acc6b549 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -41,10 +41,13 @@ namespace android { namespace { -constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID(111); -constexpr PhysicalDisplayId EXTERNAL_DISPLAY_ID(222); -constexpr PhysicalDisplayId DISPLAY_ID_64BIT(0xabcd12349876fedcULL); +constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID = PhysicalDisplayId::fromPort(111u); +constexpr PhysicalDisplayId EXTERNAL_DISPLAY_ID = PhysicalDisplayId::fromPort(222u); +constexpr PhysicalDisplayId DISPLAY_ID_64BIT = + PhysicalDisplayId::fromEdid(0xffu, 0xffffu, 0xffff'ffffu); + constexpr std::chrono::duration VSYNC_PERIOD(16ms); + class MockVSyncSource : public VSyncSource { public: const char* getName() const override { return "test"; } diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 38e503fc81..7a6ae5bbc2 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -34,7 +34,7 @@ using testing::Return; namespace android { namespace { -constexpr PhysicalDisplayId PHYSICAL_DISPLAY_ID(999); +constexpr PhysicalDisplayId PHYSICAL_DISPLAY_ID = PhysicalDisplayId::fromPort(255u); class SchedulerTest : public testing::Test { protected: -- cgit v1.2.3-59-g8ed1b From 50121d58d0ff7cee786aea0997678d2208dfdecf Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Fri, 23 Apr 2021 13:01:16 -0700 Subject: SF: Use RenderSurfaceCreationArgsBuilder Fix -Wmissing-field-initializers errors silenced via pragmas. Bug: 129481165 Test: m libcompositionengine_test Change-Id: I6b254be239b173af599c4423f190472af218dbb9 --- .../compositionengine/RenderSurfaceCreationArgs.h | 39 ++++++++-------------- .../CompositionEngine/tests/DisplayTest.cpp | 15 ++++++--- .../CompositionEngine/tests/RenderSurfaceTest.cpp | 22 +++++------- services/surfaceflinger/DisplayDevice.cpp | 15 +++++---- 4 files changed, 42 insertions(+), 49 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h index a8d372c562..4110346aa3 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h @@ -24,21 +24,17 @@ struct ANativeWindow; -namespace android { - -namespace compositionengine { - -class Display; +namespace android::compositionengine { /** * A parameter object for creating RenderSurface instances */ struct RenderSurfaceCreationArgs { // The initial width of the surface - int32_t displayWidth; + int32_t displayWidth = -1; // The initial height of the surface - int32_t displayHeight; + int32_t displayHeight = -1; // The ANativeWindow for the buffer queue for this surface sp nativeWindow; @@ -46,22 +42,16 @@ struct RenderSurfaceCreationArgs { // The DisplaySurface for this surface sp displaySurface; - size_t maxTextureCacheSize; + // The maximum size of the renderengine::ExternalTexture cache + size_t maxTextureCacheSize = 0; + +private: + friend class RenderSurfaceCreationArgsBuilder; + + // Not defaulted to disable aggregate initialization. + RenderSurfaceCreationArgs() {} }; -/** - * A helper for setting up a RenderSurfaceCreationArgs value in-line. - * Prefer this builder over raw structure initialization. - * - * Instead of: - * - * RenderSurfaceCreationArgs{1000, 1000, nativeWindow, displaySurface} - * - * Prefer: - * - * RenderSurfaceCreationArgsBuilder().setDisplayWidth(1000).setDisplayHeight(1000) - * .setNativeWindow(nativeWindow).setDisplaySurface(displaySurface).Build(); - */ class RenderSurfaceCreationArgsBuilder { public: RenderSurfaceCreationArgs build() { return std::move(mArgs); } @@ -75,11 +65,11 @@ public: return *this; } RenderSurfaceCreationArgsBuilder& setNativeWindow(sp nativeWindow) { - mArgs.nativeWindow = nativeWindow; + mArgs.nativeWindow = std::move(nativeWindow); return *this; } RenderSurfaceCreationArgsBuilder& setDisplaySurface(sp displaySurface) { - mArgs.displaySurface = displaySurface; + mArgs.displaySurface = std::move(displaySurface); return *this; } @@ -92,5 +82,4 @@ private: RenderSurfaceCreationArgs mArgs; }; -} // namespace compositionengine -} // namespace android +} // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index b31e64ac0d..492db431da 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -522,7 +522,11 @@ using DisplayCreateRenderSurfaceTest = PartialMockDisplayTestCommon; TEST_F(DisplayCreateRenderSurfaceTest, setsRenderSurface) { EXPECT_CALL(*mNativeWindow, disconnect(NATIVE_WINDOW_API_EGL)).WillRepeatedly(Return(NO_ERROR)); EXPECT_TRUE(mDisplay->getRenderSurface() == nullptr); - mDisplay->createRenderSurface(RenderSurfaceCreationArgs{640, 480, mNativeWindow, nullptr}); + mDisplay->createRenderSurface(RenderSurfaceCreationArgsBuilder() + .setDisplayWidth(640) + .setDisplayHeight(480) + .setNativeWindow(mNativeWindow) + .build()); EXPECT_TRUE(mDisplay->getRenderSurface() != nullptr); } @@ -1030,9 +1034,12 @@ struct DisplayFunctionalTest : public testing::Test { ); impl::RenderSurface* mRenderSurface = new impl::RenderSurface{mCompositionEngine, *mDisplay, - RenderSurfaceCreationArgs{DEFAULT_DISPLAY_WIDTH, - DEFAULT_DISPLAY_HEIGHT, mNativeWindow, - mDisplaySurface}}; + RenderSurfaceCreationArgsBuilder() + .setDisplayWidth(DEFAULT_DISPLAY_WIDTH) + .setDisplayHeight(DEFAULT_DISPLAY_HEIGHT) + .setNativeWindow(mNativeWindow) + .setDisplaySurface(mDisplaySurface) + .build()}; }; TEST_F(DisplayFunctionalTest, postFramebufferCriticalCallsAreOrdered) { diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index 8579d8c444..431cc93514 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -14,12 +14,6 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#include "renderengine/ExternalTexture.h" -#include "ui/GraphicBuffer.h" -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wextra" - #include #include @@ -32,7 +26,9 @@ #include #include #include +#include #include +#include namespace android::compositionengine { namespace { @@ -67,9 +63,12 @@ public: sp mNativeWindow = new StrictMock(); sp mDisplaySurface = new StrictMock(); impl::RenderSurface mSurface{mCompositionEngine, mDisplay, - RenderSurfaceCreationArgs{DEFAULT_DISPLAY_WIDTH, - DEFAULT_DISPLAY_HEIGHT, mNativeWindow, - mDisplaySurface}}; + RenderSurfaceCreationArgsBuilder() + .setDisplayWidth(DEFAULT_DISPLAY_WIDTH) + .setDisplayHeight(DEFAULT_DISPLAY_HEIGHT) + .setNativeWindow(mNativeWindow) + .setDisplaySurface(mDisplaySurface) + .build()}; }; /* @@ -367,11 +366,8 @@ TEST_F(RenderSurfaceTest, flipForwardsSignal) { mSurface.flip(); - EXPECT_EQ(501, mSurface.getPageFlipCount()); + EXPECT_EQ(501u, mSurface.getPageFlipCount()); } } // namespace } // namespace android::compositionengine - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 8692ee60dc..d8a7514c2f 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -70,13 +70,14 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) mIsPrimary(args.isPrimary) { mCompositionDisplay->editState().isSecure = args.isSecure; mCompositionDisplay->createRenderSurface( - compositionengine:: - RenderSurfaceCreationArgs{ANativeWindow_getWidth(args.nativeWindow.get()), - ANativeWindow_getHeight(args.nativeWindow.get()), - args.nativeWindow, args.displaySurface, - static_cast( - SurfaceFlinger:: - maxFrameBufferAcquiredBuffers)}); + compositionengine::RenderSurfaceCreationArgsBuilder() + .setDisplayWidth(ANativeWindow_getWidth(args.nativeWindow.get())) + .setDisplayHeight(ANativeWindow_getHeight(args.nativeWindow.get())) + .setNativeWindow(std::move(args.nativeWindow)) + .setDisplaySurface(std::move(args.displaySurface)) + .setMaxTextureCacheSize( + static_cast(SurfaceFlinger::maxFrameBufferAcquiredBuffers)) + .build()); if (!mFlinger->mDisableClientCompositionCache && SurfaceFlinger::maxFrameBufferAcquiredBuffers > 0) { -- cgit v1.2.3-59-g8ed1b From 4a63393eaec01acc580427d8477298c08ee3b349 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Tue, 27 Apr 2021 12:57:59 -0700 Subject: SF unit test: Disable flaky tests A good number of OneShotTimer tests were flaky. This changes marks them as DISABLED, with a comment linking to the bug. Bug: 186417847 Test: libsurfaceflinger_unittest # Tests marked disabled Change-Id: I75a034e6a79e0469b3a321e410ca0d6db36bd5fe --- services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp index 691676420c..597e5e71a2 100644 --- a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp +++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp @@ -72,7 +72,8 @@ TEST_F(OneShotTimerTest, startStopTest) { mIdleTimer->stop(); } -TEST_F(OneShotTimerTest, resetTest) { +// TODO(b/186417847) This test is flaky. Reenable once fixed. +TEST_F(OneShotTimerTest, DISABLED_resetTest) { fake::FakeClock* clock = new fake::FakeClock(); mIdleTimer = std::make_unique("TestTimer", 1ms, mResetTimerCallback.getInvocable(), @@ -94,7 +95,8 @@ TEST_F(OneShotTimerTest, resetTest) { EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value()); } -TEST_F(OneShotTimerTest, resetBackToBackTest) { +// TODO(b/186417847) This test is flaky. Reenable once fixed. +TEST_F(OneShotTimerTest, DISABLED_resetBackToBackTest) { fake::FakeClock* clock = new fake::FakeClock(); mIdleTimer = std::make_unique("TestTimer", 1ms, mResetTimerCallback.getInvocable(), @@ -144,7 +146,8 @@ TEST_F(OneShotTimerTest, startNotCalledTest) { EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value()); } -TEST_F(OneShotTimerTest, idleTimerIdlesTest) { +// TODO(b/186417847) This test is flaky. Reenable once fixed. +TEST_F(OneShotTimerTest, DISABLED_idleTimerIdlesTest) { fake::FakeClock* clock = new fake::FakeClock(); mIdleTimer = std::make_unique("TestTimer", 1ms, mResetTimerCallback.getInvocable(), @@ -169,7 +172,8 @@ TEST_F(OneShotTimerTest, idleTimerIdlesTest) { EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value()); } -TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) { +// TODO(b/186417847) This test is flaky. Reenable once fixed. +TEST_F(OneShotTimerTest, DISABLED_timeoutCallbackExecutionTest) { fake::FakeClock* clock = new fake::FakeClock(); mIdleTimer = std::make_unique("TestTimer", 1ms, mResetTimerCallback.getInvocable(), -- cgit v1.2.3-59-g8ed1b From dd8bf2d69562aed676dac27a9180d9b81a477e4b Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Sat, 8 May 2021 16:36:33 -0700 Subject: Support toggling layer caching at runtime The use-case for this is dynamically enabling and disabling layer caching when a bad layer state is encountered that is difficult to reproduce. Bug: 187448777 Test: adb shell service call SurfaceFlinger 1040 i32 1 Test: libcompositionengine_test Change-Id: Id441a0894ff5a4c654db9fd706ceb1c0d1c343f0 --- .../include/compositionengine/Output.h | 3 ++ .../include/compositionengine/impl/Output.h | 8 ++--- .../include/compositionengine/mock/Output.h | 1 + .../CompositionEngine/src/Output.cpp | 27 ++++++++------- .../CompositionEngine/tests/OutputTest.cpp | 26 +++++++++++++-- services/surfaceflinger/DisplayDevice.cpp | 4 +++ services/surfaceflinger/DisplayDevice.h | 3 ++ services/surfaceflinger/SurfaceFlinger.cpp | 38 ++++++++++++++++++++-- services/surfaceflinger/SurfaceFlinger.h | 1 + 9 files changed, 89 insertions(+), 22 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 497621397c..9fba7aa558 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -163,6 +163,9 @@ public: // Enables (or disables) composition on this output virtual void setCompositionEnabled(bool) = 0; + // Enables (or disables) layer caching on this output + virtual void setLayerCachingEnabled(bool) = 0; + // Sets the projection state to use virtual void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect, const Rect& orientedDisplaySpaceRect) = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index eeb20fc1d1..2893c3f910 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -28,21 +29,18 @@ namespace android::compositionengine::impl { -namespace planner { -class Planner; -} // namespace planner - // The implementation class contains the common implementation, but does not // actually contain the final output state. class Output : public virtual compositionengine::Output { public: - Output(); + Output() = default; ~Output() override; // compositionengine::Output overrides bool isValid() const override; std::optional getDisplayId() const override; void setCompositionEnabled(bool) override; + void setLayerCachingEnabled(bool) override; void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect, const Rect& orientedDisplaySpaceRect) override; void setDisplaySize(const ui::Size&) override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 5aa53e54dd..749675d8fd 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -36,6 +36,7 @@ public: MOCK_CONST_METHOD0(getDisplayId, std::optional()); MOCK_METHOD1(setCompositionEnabled, void(bool)); + MOCK_METHOD1(setLayerCachingEnabled, void(bool)); MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&)); MOCK_METHOD1(setDisplaySize, void(const ui::Size&)); MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool)); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 297e687fcb..796fe7dbf0 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -55,18 +55,6 @@ Output::~Output() = default; namespace impl { -Output::Output() { - const bool enableLayerCaching = [] { - const bool enable = - android::sysprop::SurfaceFlingerProperties::enable_layer_caching().value_or(false); - return base::GetBoolProperty(std::string("debug.sf.enable_layer_caching"), enable); - }(); - - if (enableLayerCaching) { - mPlanner = std::make_unique(); - } -} - namespace { template @@ -135,6 +123,21 @@ void Output::setCompositionEnabled(bool enabled) { dirtyEntireOutput(); } +void Output::setLayerCachingEnabled(bool enabled) { + if (enabled == (mPlanner != nullptr)) { + return; + } + + if (enabled) { + mPlanner = std::make_unique(); + if (mRenderSurface) { + mPlanner->setDisplaySize(mRenderSurface->getSize()); + } + } else { + mPlanner.reset(); + } +} + void Output::setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect, const Rect& orientedDisplaySpaceRect) { auto& outputState = editState(); diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 27980a01ac..11736d1e07 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -237,6 +237,28 @@ TEST_F(OutputTest, setCompositionEnabledSetsDisabledAndDirtiesEntireOutput) { EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } +/* + * Output::setLayerCachingEnabled() + */ + +TEST_F(OutputTest, setLayerCachingEnabled_enablesCaching) { + const auto kSize = ui::Size(1, 1); + EXPECT_CALL(*mRenderSurface, getSize()).WillRepeatedly(ReturnRef(kSize)); + mOutput->setLayerCachingEnabled(false); + mOutput->setLayerCachingEnabled(true); + + EXPECT_TRUE(mOutput->plannerEnabled()); +} + +TEST_F(OutputTest, setLayerCachingEnabled_disablesCaching) { + const auto kSize = ui::Size(1, 1); + EXPECT_CALL(*mRenderSurface, getSize()).WillRepeatedly(ReturnRef(kSize)); + mOutput->setLayerCachingEnabled(true); + mOutput->setLayerCachingEnabled(false); + + EXPECT_FALSE(mOutput->plannerEnabled()); +} + /* * Output::setProjection() */ @@ -972,9 +994,7 @@ TEST_F(OutputPrepareFrameTest, delegatesToChooseCompositionStrategyAndRenderSurf mOutput.editState().usesDeviceComposition = true; EXPECT_CALL(mOutput, chooseCompositionStrategy()).Times(1); - if (mOutput.plannerEnabled()) { - EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u)); - } + EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u)); EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)); mOutput.prepareFrame(); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index d8a7514c2f..339701188a 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -139,6 +139,10 @@ void DisplayDevice::setPowerMode(hal::PowerMode mode) { getCompositionDisplay()->setCompositionEnabled(mPowerMode != hal::PowerMode::OFF); } +void DisplayDevice::enableLayerCaching(bool enable) { + getCompositionDisplay()->setLayerCachingEnabled(enable); +} + hal::PowerMode DisplayDevice::getPowerMode() const { return mPowerMode; } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 68846d35bd..bf249cdb25 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -157,6 +157,9 @@ public: void setPowerMode(hardware::graphics::composer::hal::PowerMode mode); bool isPoweredOn() const; + // Enables layer caching on this DisplayDevice + void enableLayerCaching(bool enable); + ui::Dataspace getCompositionDataSpace() const; /* ------------------------------------------------------------------------ diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5bd43e133f..1e39d05a16 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -381,6 +381,12 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mColorSpaceAgnosticDataspace = static_cast(color_space_agnostic_dataspace(Dataspace::UNKNOWN)); + mLayerCachingEnabled = [] { + const bool enable = + android::sysprop::SurfaceFlingerProperties::enable_layer_caching().value_or(false); + return base::GetBoolProperty(std::string("debug.sf.enable_layer_caching"), enable); + }(); + useContextPriority = use_context_priority(true); using Values = SurfaceFlingerProperties::primary_display_orientation_values; @@ -2641,6 +2647,7 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, builder.setGpuVirtualDisplayIdGenerator(mGpuVirtualDisplayIdGenerator); builder.setName(state.displayName); const auto compositionDisplay = getCompositionEngine().createDisplay(builder.build()); + compositionDisplay->setLayerCachingEnabled(mLayerCachingEnabled); sp displaySurface; sp producer; @@ -5186,9 +5193,9 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { code == IBinder::SYSPROPS_TRANSACTION) { return OK; } - // Numbers from 1000 to 1038 are currently used for backdoors. The code + // Numbers from 1000 to 1040 are currently used for backdoors. The code // in onTransact verifies that the user is root, and has access to use SF. - if (code >= 1000 && code <= 1039) { + if (code >= 1000 && code <= 1040) { ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code); return OK; } @@ -5572,6 +5579,33 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId); return NO_ERROR; } + // Toggle caching feature + // First argument is an int32 - nonzero enables caching and zero disables caching + // Second argument is an optional uint64 - if present, then limits enabling/disabling + // caching to a particular physical display + case 1040: { + n = data.readInt32(); + std::optional inputId = std::nullopt; + if (uint64_t inputDisplayId; data.readUint64(&inputDisplayId) == NO_ERROR) { + inputId = DisplayId::fromValue(inputDisplayId); + if (!inputId || getPhysicalDisplayToken(*inputId)) { + ALOGE("No display with id: %" PRIu64, inputDisplayId); + return NAME_NOT_FOUND; + } + } + { + Mutex::Autolock lock(mStateLock); + mLayerCachingEnabled = n != 0; + for (const auto& [_, display] : mDisplays) { + if (!inputId || *inputId == display->getPhysicalId()) { + display->enableLayerCaching(mLayerCachingEnabled); + } + } + } + invalidateHwcGeometry(); + repaintEverything(); + return NO_ERROR; + } } } return err; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 0a6a8e79f7..4009bafea1 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1244,6 +1244,7 @@ private: int mDebugRegion = 0; bool mDebugDisableHWC = false; bool mDebugDisableTransformHint = false; + bool mLayerCachingEnabled = false; volatile nsecs_t mDebugInTransaction = 0; bool mForceFullDamage = false; bool mPropagateBackpressureClientComposition = false; -- cgit v1.2.3-59-g8ed1b From 3dce4f4e3bef25ac3d44aea84e14e89c5762c16d Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Mon, 8 Mar 2021 20:48:28 -0800 Subject: SF: Extract virtual display allocation from CE Allocate HAL virtual display and generate HAL/GPU virtual display ID in SF rather than CE. This centralizes the HAL vs. GPU decision as a first step in isolating display configuration (e.g. hotplug, modeset) to be a distinct stage from invalidate/refresh. Rework SF backend hooks for screen capture. Plumb the PhysicalDisplayId to be mirrored by the virtual display to Composer::createVirtualDisplay. This enables the ARC backend to know which display to mirror (instead of making assumptions about the layer stack) or error out if not mirroring (previously done through maybeAllocateDisplayIdForVirtualDisplay), such that SF falls back to creating a GPU virtual display. Bug: 182939859 Bug: 129481165 Test: Enable overlay display and toggle HAL/GPU Test: libsurfaceflinger_unittest Test: libcompositionengine_test Change-Id: I209b245966e544d5ff55d5d118140cfcfa85db15 --- .../compositionengine/DisplayCreationArgs.h | 45 +--- .../include/compositionengine/impl/Display.h | 6 - .../CompositionEngine/src/Display.cpp | 41 +-- .../CompositionEngine/tests/DisplayTest.cpp | 275 +++++++++------------ .../CompositionEngine/tests/MockHWComposer.h | 8 +- services/surfaceflinger/DisplayDevice.h | 18 +- .../surfaceflinger/DisplayHardware/ComposerHal.cpp | 5 +- .../surfaceflinger/DisplayHardware/ComposerHal.h | 7 +- .../surfaceflinger/DisplayHardware/HWComposer.cpp | 68 ++--- .../surfaceflinger/DisplayHardware/HWComposer.h | 26 +- services/surfaceflinger/DisplayIdGenerator.h | 34 ++- services/surfaceflinger/SurfaceFlinger.cpp | 136 +++++++--- services/surfaceflinger/SurfaceFlinger.h | 19 +- .../tests/unittests/CompositionTest.cpp | 32 +-- .../tests/unittests/DisplayIdGeneratorTest.cpp | 68 +++-- .../tests/unittests/DisplayTransactionTest.cpp | 39 +-- .../unittests/DisplayTransactionTestHelpers.h | 64 ++--- .../tests/unittests/FpsReporterTest.cpp | 15 +- .../tests/unittests/HWComposerTest.cpp | 4 +- .../tests/unittests/RefreshRateSelectionTest.cpp | 12 +- .../tests/unittests/SetFrameRateTest.cpp | 13 +- .../tests/unittests/TestableSurfaceFlinger.h | 8 +- .../tests/unittests/TransactionFrameTracerTest.cpp | 12 +- .../unittests/TransactionSurfaceFrameTest.cpp | 12 +- .../unittests/mock/DisplayHardware/MockComposer.h | 3 +- .../tests/unittests/mock/MockDisplayIdGenerator.h | 36 --- 26 files changed, 422 insertions(+), 584 deletions(-) delete mode 100644 services/surfaceflinger/tests/unittests/mock/MockDisplayIdGenerator.h diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h index 317d333878..526e7daa80 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h @@ -21,13 +21,10 @@ #include #include -#include #include #include -#include "DisplayHardware/DisplayIdentification.h" #include "DisplayHardware/PowerAdvisor.h" -#include "DisplayIdGenerator.h" namespace android::compositionengine { @@ -37,24 +34,14 @@ class CompositionEngine; * A parameter object for creating Display instances */ struct DisplayCreationArgs { - struct Physical { - DisplayId id; - ui::DisplayConnectionType type; - }; + DisplayId id; - // Required for physical displays. Gives the HWC display id for the existing - // display along with the connection type. - std::optional physical; + // Unset for virtual displays + std::optional connectionType; // Size of the display in pixels ui::Size pixels = ui::kInvalidSize; - // Pixel format of the display - ui::PixelFormat pixelFormat = static_cast(PIXEL_FORMAT_UNKNOWN); - - // True if virtual displays should be created with the HWC API if possible - bool useHwcVirtualDisplays = false; - // True if this display should be considered secure bool isSecure = false; @@ -67,9 +54,6 @@ struct DisplayCreationArgs { // Debugging. Human readable name for the display. std::string name; - - // Generator for IDs of virtual displays, which are backed by the GPU. - DisplayIdGenerator* gpuVirtualDisplayIdGenerator; }; /** @@ -80,29 +64,18 @@ class DisplayCreationArgsBuilder { public: DisplayCreationArgs build() { return std::move(mArgs); } - DisplayCreationArgsBuilder& setPhysical(DisplayCreationArgs::Physical physical) { - mArgs.physical = physical; + DisplayCreationArgsBuilder& setId(DisplayId id) { + mArgs.id = id; return *this; } - DisplayCreationArgsBuilder& setPixels(ui::Size pixels) { - mArgs.pixels = pixels; + DisplayCreationArgsBuilder& setConnectionType(ui::DisplayConnectionType connectionType) { + mArgs.connectionType = connectionType; return *this; } - DisplayCreationArgsBuilder& setPixelFormat(ui::PixelFormat pixelFormat) { - mArgs.pixelFormat = pixelFormat; - return *this; - } - - DisplayCreationArgsBuilder& setUseHwcVirtualDisplays(bool useHwcVirtualDisplays) { - mArgs.useHwcVirtualDisplays = useHwcVirtualDisplays; - return *this; - } - - DisplayCreationArgsBuilder& setGpuVirtualDisplayIdGenerator( - DisplayIdGenerator& generator) { - mArgs.gpuVirtualDisplayIdGenerator = &generator; + DisplayCreationArgsBuilder& setPixels(ui::Size pixels) { + mArgs.pixels = pixels; return *this; } diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index 54e91ae6be..bb540ea7ee 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -80,19 +80,13 @@ public: // Internal virtual void setConfiguration(const compositionengine::DisplayCreationArgs&); - virtual std::optional maybeAllocateDisplayIdForVirtualDisplay(ui::Size, - ui::PixelFormat) const; std::unique_ptr createOutputLayer(const sp&) const; - // Testing - void setDisplayIdForTesting(DisplayId displayId); - private: bool mIsVirtual = false; bool mIsDisconnected = false; DisplayId mId; Hwc2::PowerAdvisor* mPowerAdvisor = nullptr; - DisplayIdGenerator* mGpuVirtualDisplayIdGenerator; }; // This template factory function standardizes the implementation details of the diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 1ffb1c8e2d..7d84cb56d3 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -50,36 +50,14 @@ std::shared_ptr createDisplay( Display::~Display() = default; void Display::setConfiguration(const compositionengine::DisplayCreationArgs& args) { - mIsVirtual = !args.physical; + mId = args.id; + mIsVirtual = !args.connectionType; mPowerAdvisor = args.powerAdvisor; editState().isSecure = args.isSecure; editState().displaySpace.bounds = Rect(args.pixels); setLayerStackFilter(args.layerStackId, - args.physical && - args.physical->type == ui::DisplayConnectionType::Internal); + args.connectionType == ui::DisplayConnectionType::Internal); setName(args.name); - mGpuVirtualDisplayIdGenerator = args.gpuVirtualDisplayIdGenerator; - - if (args.physical) { - mId = args.physical->id; - } else { - std::optional id; - if (args.useHwcVirtualDisplays) { - id = maybeAllocateDisplayIdForVirtualDisplay(args.pixels, args.pixelFormat); - } - if (!id) { - id = mGpuVirtualDisplayIdGenerator->nextId(); - } - LOG_ALWAYS_FATAL_IF(!id, "Failed to generate display ID"); - mId = *id; - } -} - -std::optional Display::maybeAllocateDisplayIdForVirtualDisplay( - ui::Size pixels, ui::PixelFormat pixelFormat) const { - auto& hwc = getCompositionEngine().getHwComposer(); - return hwc.allocateVirtualDisplay(static_cast(pixels.width), - static_cast(pixels.height), &pixelFormat); } bool Display::isValid() const { @@ -102,23 +80,16 @@ std::optional Display::getDisplayId() const { return mId; } -void Display::setDisplayIdForTesting(DisplayId displayId) { - mId = displayId; -} - void Display::disconnect() { if (mIsDisconnected) { return; } mIsDisconnected = true; - if (const auto id = GpuVirtualDisplayId::tryCast(mId)) { - mGpuVirtualDisplayIdGenerator->markUnused(*id); - return; + + if (const auto id = HalDisplayId::tryCast(mId)) { + getCompositionEngine().getHwComposer().disconnectDisplay(*id); } - const auto halDisplayId = HalDisplayId::tryCast(mId); - LOG_FATAL_IF(!halDisplayId); - getCompositionEngine().getHwComposer().disconnectDisplay(*halDisplayId); } void Display::setColorTransform(const compositionengine::CompositionRefreshArgs& args) { diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 492db431da..5c9421b54c 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -14,10 +14,6 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wextra" - #include #include @@ -60,13 +56,12 @@ using testing::Sequence; using testing::SetArgPointee; using testing::StrictMock; -constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u); -// TODO(b/160679868) Use VirtualDisplayId -constexpr PhysicalDisplayId VIRTUAL_DISPLAY_ID = PhysicalDisplayId::fromPort(43u); +constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(123u); +constexpr HalVirtualDisplayId HAL_VIRTUAL_DISPLAY_ID{456u}; +constexpr GpuVirtualDisplayId GPU_VIRTUAL_DISPLAY_ID{789u}; -constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920; -constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080; -constexpr int32_t DEFAULT_LAYER_STACK = 123; +constexpr ui::Size DEFAULT_RESOLUTION{1920, 1080}; +constexpr uint32_t DEFAULT_LAYER_STACK = 42; struct Layer { Layer() { @@ -95,8 +90,6 @@ struct DisplayTestCommon : public testing::Test { public: using impl::Display::injectOutputLayerForTest; virtual void injectOutputLayerForTest(std::unique_ptr) = 0; - - using impl::Display::maybeAllocateDisplayIdForVirtualDisplay; }; // Uses a special implementation with key internal member functions set up @@ -170,21 +163,19 @@ struct DisplayTestCommon : public testing::Test { DisplayCreationArgs getDisplayCreationArgsForPhysicalHWCDisplay() { return DisplayCreationArgsBuilder() - .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal}) - .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) - .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) + .setId(DEFAULT_DISPLAY_ID) + .setConnectionType(ui::DisplayConnectionType::Internal) + .setPixels(DEFAULT_RESOLUTION) .setIsSecure(true) .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&mPowerAdvisor) .build(); } - DisplayCreationArgs getDisplayCreationArgsForNonHWCVirtualDisplay() { + DisplayCreationArgs getDisplayCreationArgsForGpuVirtualDisplay() { return DisplayCreationArgsBuilder() - .setUseHwcVirtualDisplays(false) - .setGpuVirtualDisplayIdGenerator(mGpuDisplayIdGenerator) - .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) - .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) + .setId(GPU_VIRTUAL_DISPLAY_ID) + .setPixels(DEFAULT_RESOLUTION) .setIsSecure(false) .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&mPowerAdvisor) @@ -196,7 +187,6 @@ struct DisplayTestCommon : public testing::Test { StrictMock mRenderEngine; StrictMock mCompositionEngine; sp mNativeWindow = new StrictMock(); - RandomDisplayIdGenerator mGpuDisplayIdGenerator; }; struct PartialMockDisplayTestCommon : public DisplayTestCommon { @@ -248,9 +238,9 @@ TEST_F(DisplayCreationTest, createPhysicalInternalDisplay) { EXPECT_EQ(DEFAULT_DISPLAY_ID, display->getId()); } -TEST_F(DisplayCreationTest, createNonHwcVirtualDisplay) { - auto display = impl::createDisplay(mCompositionEngine, - getDisplayCreationArgsForNonHWCVirtualDisplay()); +TEST_F(DisplayCreationTest, createGpuVirtualDisplay) { + auto display = + impl::createDisplay(mCompositionEngine, getDisplayCreationArgsForGpuVirtualDisplay()); EXPECT_FALSE(display->isSecure()); EXPECT_TRUE(display->isVirtual()); EXPECT_TRUE(GpuVirtualDisplayId::tryCast(display->getId())); @@ -263,17 +253,15 @@ TEST_F(DisplayCreationTest, createNonHwcVirtualDisplay) { using DisplaySetConfigurationTest = PartialMockDisplayTestCommon; TEST_F(DisplaySetConfigurationTest, configuresInternalSecurePhysicalDisplay) { - mDisplay->setConfiguration( - DisplayCreationArgsBuilder() - .setUseHwcVirtualDisplays(true) - .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal}) - .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH)) - .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) - .setIsSecure(true) - .setLayerStackId(DEFAULT_LAYER_STACK) - .setPowerAdvisor(&mPowerAdvisor) - .setName(getDisplayNameFromCurrentTest()) - .build()); + mDisplay->setConfiguration(DisplayCreationArgsBuilder() + .setId(DEFAULT_DISPLAY_ID) + .setConnectionType(ui::DisplayConnectionType::Internal) + .setPixels(DEFAULT_RESOLUTION) + .setIsSecure(true) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .setName(getDisplayNameFromCurrentTest()) + .build()); EXPECT_EQ(DEFAULT_DISPLAY_ID, mDisplay->getId()); EXPECT_TRUE(mDisplay->isSecure()); @@ -284,17 +272,15 @@ TEST_F(DisplaySetConfigurationTest, configuresInternalSecurePhysicalDisplay) { } TEST_F(DisplaySetConfigurationTest, configuresExternalInsecurePhysicalDisplay) { - mDisplay->setConfiguration( - DisplayCreationArgsBuilder() - .setUseHwcVirtualDisplays(true) - .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::External}) - .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH)) - .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) - .setIsSecure(false) - .setLayerStackId(DEFAULT_LAYER_STACK) - .setPowerAdvisor(&mPowerAdvisor) - .setName(getDisplayNameFromCurrentTest()) - .build()); + mDisplay->setConfiguration(DisplayCreationArgsBuilder() + .setId(DEFAULT_DISPLAY_ID) + .setConnectionType(ui::DisplayConnectionType::External) + .setPixels(DEFAULT_RESOLUTION) + .setIsSecure(false) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .setName(getDisplayNameFromCurrentTest()) + .build()); EXPECT_EQ(DEFAULT_DISPLAY_ID, mDisplay->getId()); EXPECT_FALSE(mDisplay->isSecure()); @@ -304,52 +290,17 @@ TEST_F(DisplaySetConfigurationTest, configuresExternalInsecurePhysicalDisplay) { EXPECT_FALSE(mDisplay->isValid()); } -TEST_F(DisplaySetConfigurationTest, configuresHwcBackedVirtualDisplay) { - EXPECT_CALL(mHwComposer, - allocateVirtualDisplay(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH, - Pointee(Eq(static_cast( - PIXEL_FORMAT_RGBA_8888))))) - .WillOnce(Return(VIRTUAL_DISPLAY_ID)); - - mDisplay->setConfiguration( - DisplayCreationArgsBuilder() - .setUseHwcVirtualDisplays(true) - .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH)) - .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) - .setIsSecure(false) - .setLayerStackId(DEFAULT_LAYER_STACK) - .setPowerAdvisor(&mPowerAdvisor) - .setName(getDisplayNameFromCurrentTest()) - .build()); - - EXPECT_EQ(VIRTUAL_DISPLAY_ID, mDisplay->getId()); - EXPECT_FALSE(mDisplay->isSecure()); - EXPECT_TRUE(mDisplay->isVirtual()); - EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); - EXPECT_FALSE(mDisplay->getState().layerStackInternal); - EXPECT_FALSE(mDisplay->isValid()); -} +TEST_F(DisplaySetConfigurationTest, configuresHalVirtualDisplay) { + mDisplay->setConfiguration(DisplayCreationArgsBuilder() + .setId(HAL_VIRTUAL_DISPLAY_ID) + .setPixels(DEFAULT_RESOLUTION) + .setIsSecure(false) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .setName(getDisplayNameFromCurrentTest()) + .build()); -TEST_F(DisplaySetConfigurationTest, configuresNonHwcBackedVirtualDisplayIfHwcAllocationFails) { - EXPECT_CALL(mHwComposer, - allocateVirtualDisplay(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH, - Pointee(Eq(static_cast( - PIXEL_FORMAT_RGBA_8888))))) - .WillOnce(Return(std::nullopt)); - - mDisplay->setConfiguration( - DisplayCreationArgsBuilder() - .setUseHwcVirtualDisplays(true) - .setGpuVirtualDisplayIdGenerator(mGpuDisplayIdGenerator) - .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH)) - .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) - .setIsSecure(false) - .setLayerStackId(DEFAULT_LAYER_STACK) - .setPowerAdvisor(&mPowerAdvisor) - .setName(getDisplayNameFromCurrentTest()) - .build()); - - EXPECT_TRUE(GpuVirtualDisplayId::tryCast(mDisplay->getId())); + EXPECT_EQ(HAL_VIRTUAL_DISPLAY_ID, mDisplay->getId()); EXPECT_FALSE(mDisplay->isSecure()); EXPECT_TRUE(mDisplay->isVirtual()); EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); @@ -357,20 +308,17 @@ TEST_F(DisplaySetConfigurationTest, configuresNonHwcBackedVirtualDisplayIfHwcAll EXPECT_FALSE(mDisplay->isValid()); } -TEST_F(DisplaySetConfigurationTest, configuresNonHwcBackedVirtualDisplayIfShouldNotUseHwc) { - mDisplay->setConfiguration( - DisplayCreationArgsBuilder() - .setUseHwcVirtualDisplays(false) - .setGpuVirtualDisplayIdGenerator(mGpuDisplayIdGenerator) - .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH)) - .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) - .setIsSecure(false) - .setLayerStackId(DEFAULT_LAYER_STACK) - .setPowerAdvisor(&mPowerAdvisor) - .setName(getDisplayNameFromCurrentTest()) - .build()); - - EXPECT_TRUE(GpuVirtualDisplayId::tryCast(mDisplay->getId())); +TEST_F(DisplaySetConfigurationTest, configuresGpuVirtualDisplay) { + mDisplay->setConfiguration(DisplayCreationArgsBuilder() + .setId(GPU_VIRTUAL_DISPLAY_ID) + .setPixels(DEFAULT_RESOLUTION) + .setIsSecure(false) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .setName(getDisplayNameFromCurrentTest()) + .build()); + + EXPECT_EQ(GPU_VIRTUAL_DISPLAY_ID, mDisplay->getId()); EXPECT_FALSE(mDisplay->isSecure()); EXPECT_TRUE(mDisplay->isVirtual()); EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); @@ -477,7 +425,7 @@ TEST_F(DisplaySetColorModeTest, setsModeUnlessNoChange) { TEST_F(DisplaySetColorModeTest, doesNothingForVirtualDisplay) { using ColorProfile = Output::ColorProfile; - auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); + auto args = getDisplayCreationArgsForGpuVirtualDisplay(); std::shared_ptr virtualDisplay = impl::createDisplay(mCompositionEngine, args); mock::DisplayColorProfile* colorProfile = new StrictMock(); @@ -557,25 +505,25 @@ TEST_F(DisplayCreateOutputLayerTest, setsHwcLayer) { using DisplaySetReleasedLayersTest = DisplayWithLayersTestCommon; -TEST_F(DisplaySetReleasedLayersTest, doesNothingIfNotHwcDisplay) { - auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); - std::shared_ptr nonHwcDisplay = impl::createDisplay(mCompositionEngine, args); +TEST_F(DisplaySetReleasedLayersTest, doesNothingIfGpuDisplay) { + auto args = getDisplayCreationArgsForGpuVirtualDisplay(); + std::shared_ptr gpuDisplay = impl::createDisplay(mCompositionEngine, args); sp layerXLayerFE = new StrictMock(); { Output::ReleasedLayers releasedLayers; releasedLayers.emplace_back(layerXLayerFE); - nonHwcDisplay->setReleasedLayers(std::move(releasedLayers)); + gpuDisplay->setReleasedLayers(std::move(releasedLayers)); } CompositionRefreshArgs refreshArgs; refreshArgs.layersWithQueuedFrames.push_back(layerXLayerFE); - nonHwcDisplay->setReleasedLayers(refreshArgs); + gpuDisplay->setReleasedLayers(refreshArgs); - const auto& releasedLayers = nonHwcDisplay->getReleasedLayersForTest(); - ASSERT_EQ(1, releasedLayers.size()); + const auto& releasedLayers = gpuDisplay->getReleasedLayersForTest(); + ASSERT_EQ(1u, releasedLayers.size()); } TEST_F(DisplaySetReleasedLayersTest, doesNothingIfNoLayersWithQueuedFrames) { @@ -591,7 +539,7 @@ TEST_F(DisplaySetReleasedLayersTest, doesNothingIfNoLayersWithQueuedFrames) { mDisplay->setReleasedLayers(refreshArgs); const auto& releasedLayers = mDisplay->getReleasedLayersForTest(); - ASSERT_EQ(1, releasedLayers.size()); + ASSERT_EQ(1u, releasedLayers.size()); } TEST_F(DisplaySetReleasedLayersTest, setReleasedLayers) { @@ -605,7 +553,7 @@ TEST_F(DisplaySetReleasedLayersTest, setReleasedLayers) { mDisplay->setReleasedLayers(refreshArgs); const auto& releasedLayers = mDisplay->getReleasedLayersForTest(); - ASSERT_EQ(2, releasedLayers.size()); + ASSERT_EQ(2u, releasedLayers.size()); ASSERT_EQ(mLayer1.layerFE.get(), releasedLayers[0].promote().get()); ASSERT_EQ(mLayer2.layerFE.get(), releasedLayers[1].promote().get()); } @@ -616,15 +564,15 @@ TEST_F(DisplaySetReleasedLayersTest, setReleasedLayers) { using DisplayChooseCompositionStrategyTest = PartialMockDisplayTestCommon; -TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfNotAHwcDisplay) { - auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); - std::shared_ptr nonHwcDisplay = +TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfGpuDisplay) { + auto args = getDisplayCreationArgsForGpuVirtualDisplay(); + std::shared_ptr gpuDisplay = createPartialMockDisplay(mCompositionEngine, args); - EXPECT_TRUE(GpuVirtualDisplayId::tryCast(nonHwcDisplay->getId())); + EXPECT_TRUE(GpuVirtualDisplayId::tryCast(gpuDisplay->getId())); - nonHwcDisplay->chooseCompositionStrategy(); + gpuDisplay->chooseCompositionStrategy(); - auto& state = nonHwcDisplay->getState(); + auto& state = gpuDisplay->getState(); EXPECT_TRUE(state.usesClientComposition); EXPECT_FALSE(state.usesDeviceComposition); } @@ -704,12 +652,12 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { using DisplayGetSkipColorTransformTest = DisplayWithLayersTestCommon; -TEST_F(DisplayGetSkipColorTransformTest, checksCapabilityIfNonHwcDisplay) { +TEST_F(DisplayGetSkipColorTransformTest, checksCapabilityIfGpuDisplay) { EXPECT_CALL(mHwComposer, hasCapability(hal::Capability::SKIP_CLIENT_COLOR_TRANSFORM)) .WillOnce(Return(true)); - auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); - auto nonHwcDisplay{impl::createDisplay(mCompositionEngine, args)}; - EXPECT_TRUE(nonHwcDisplay->getSkipColorTransform()); + auto args = getDisplayCreationArgsForGpuVirtualDisplay(); + auto gpuDisplay{impl::createDisplay(mCompositionEngine, args)}; + EXPECT_TRUE(gpuDisplay->getSkipColorTransform()); } TEST_F(DisplayGetSkipColorTransformTest, checksDisplayCapability) { @@ -856,11 +804,11 @@ TEST_F(DisplayApplyLayerRequestsToLayersTest, appliesDeviceLayerRequests) { using DisplayPresentAndGetFrameFencesTest = DisplayWithLayersTestCommon; -TEST_F(DisplayPresentAndGetFrameFencesTest, returnsNoFencesOnNonHwcDisplay) { - auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); - auto nonHwcDisplay{impl::createDisplay(mCompositionEngine, args)}; +TEST_F(DisplayPresentAndGetFrameFencesTest, returnsNoFencesOnGpuDisplay) { + auto args = getDisplayCreationArgsForGpuVirtualDisplay(); + auto gpuDisplay{impl::createDisplay(mCompositionEngine, args)}; - auto result = nonHwcDisplay->presentAndGetFrameFences(); + auto result = gpuDisplay->presentAndGetFrameFences(); ASSERT_TRUE(result.presentFence.get()); EXPECT_FALSE(result.presentFence->isValid()); @@ -888,9 +836,9 @@ TEST_F(DisplayPresentAndGetFrameFencesTest, returnsPresentAndLayerFences) { EXPECT_EQ(presentFence, result.presentFence); EXPECT_EQ(2u, result.layerFences.size()); - ASSERT_EQ(1, result.layerFences.count(&mLayer1.hwc2Layer)); + ASSERT_EQ(1u, result.layerFences.count(&mLayer1.hwc2Layer)); EXPECT_EQ(layer1Fence, result.layerFences[&mLayer1.hwc2Layer]); - ASSERT_EQ(1, result.layerFences.count(&mLayer2.hwc2Layer)); + ASSERT_EQ(1u, result.layerFences.count(&mLayer2.hwc2Layer)); EXPECT_EQ(layer2Fence, result.layerFences[&mLayer2.hwc2Layer]); } @@ -936,66 +884,66 @@ TEST_F(DisplayFinishFrameTest, doesNotSkipCompositionIfNotDirtyOnHwcDisplay) { } TEST_F(DisplayFinishFrameTest, skipsCompositionIfNotDirty) { - auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); - std::shared_ptr nonHwcDisplay = impl::createDisplay(mCompositionEngine, args); + auto args = getDisplayCreationArgsForGpuVirtualDisplay(); + std::shared_ptr gpuDisplay = impl::createDisplay(mCompositionEngine, args); mock::RenderSurface* renderSurface = new StrictMock(); - nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr(renderSurface)); + gpuDisplay->setRenderSurfaceForTest(std::unique_ptr(renderSurface)); // We expect no calls to queueBuffer if composition was skipped. EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(0); - nonHwcDisplay->editState().isEnabled = true; - nonHwcDisplay->editState().usesClientComposition = false; - nonHwcDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1); - nonHwcDisplay->editState().dirtyRegion = Region::INVALID_REGION; + gpuDisplay->editState().isEnabled = true; + gpuDisplay->editState().usesClientComposition = false; + gpuDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1); + gpuDisplay->editState().dirtyRegion = Region::INVALID_REGION; CompositionRefreshArgs refreshArgs; refreshArgs.repaintEverything = false; - nonHwcDisplay->finishFrame(refreshArgs); + gpuDisplay->finishFrame(refreshArgs); } TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) { - auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); - std::shared_ptr nonHwcDisplay = impl::createDisplay(mCompositionEngine, args); + auto args = getDisplayCreationArgsForGpuVirtualDisplay(); + std::shared_ptr gpuDisplay = impl::createDisplay(mCompositionEngine, args); mock::RenderSurface* renderSurface = new StrictMock(); - nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr(renderSurface)); + gpuDisplay->setRenderSurfaceForTest(std::unique_ptr(renderSurface)); // We expect a single call to queueBuffer when composition is not skipped. EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1); - nonHwcDisplay->editState().isEnabled = true; - nonHwcDisplay->editState().usesClientComposition = false; - nonHwcDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1); - nonHwcDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1)); + gpuDisplay->editState().isEnabled = true; + gpuDisplay->editState().usesClientComposition = false; + gpuDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1); + gpuDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1)); CompositionRefreshArgs refreshArgs; refreshArgs.repaintEverything = false; - nonHwcDisplay->finishFrame(refreshArgs); + gpuDisplay->finishFrame(refreshArgs); } TEST_F(DisplayFinishFrameTest, performsCompositionIfRepaintEverything) { - auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); - std::shared_ptr nonHwcDisplay = impl::createDisplay(mCompositionEngine, args); + auto args = getDisplayCreationArgsForGpuVirtualDisplay(); + std::shared_ptr gpuDisplay = impl::createDisplay(mCompositionEngine, args); mock::RenderSurface* renderSurface = new StrictMock(); - nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr(renderSurface)); + gpuDisplay->setRenderSurfaceForTest(std::unique_ptr(renderSurface)); // We expect a single call to queueBuffer when composition is not skipped. EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1); - nonHwcDisplay->editState().isEnabled = true; - nonHwcDisplay->editState().usesClientComposition = false; - nonHwcDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1); - nonHwcDisplay->editState().dirtyRegion = Region::INVALID_REGION; + gpuDisplay->editState().isEnabled = true; + gpuDisplay->editState().usesClientComposition = false; + gpuDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1); + gpuDisplay->editState().dirtyRegion = Region::INVALID_REGION; CompositionRefreshArgs refreshArgs; refreshArgs.repaintEverything = true; - nonHwcDisplay->finishFrame(refreshArgs); + gpuDisplay->finishFrame(refreshArgs); } /* @@ -1020,23 +968,23 @@ struct DisplayFunctionalTest : public testing::Test { NiceMock mCompositionEngine; sp mNativeWindow = new NiceMock(); sp mDisplaySurface = new NiceMock(); + std::shared_ptr mDisplay = impl::createDisplayTemplated< Display>(mCompositionEngine, DisplayCreationArgsBuilder() - .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal}) - .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) - .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) + .setId(DEFAULT_DISPLAY_ID) + .setConnectionType(ui::DisplayConnectionType::Internal) + .setPixels(DEFAULT_RESOLUTION) .setIsSecure(true) .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&mPowerAdvisor) - .build() + .build()); - ); impl::RenderSurface* mRenderSurface = new impl::RenderSurface{mCompositionEngine, *mDisplay, RenderSurfaceCreationArgsBuilder() - .setDisplayWidth(DEFAULT_DISPLAY_WIDTH) - .setDisplayHeight(DEFAULT_DISPLAY_HEIGHT) + .setDisplayWidth(DEFAULT_RESOLUTION.width) + .setDisplayHeight(DEFAULT_RESOLUTION.height) .setNativeWindow(mNativeWindow) .setDisplaySurface(mDisplaySurface) .build()}; @@ -1055,6 +1003,3 @@ TEST_F(DisplayFunctionalTest, postFramebufferCriticalCallsAreOrdered) { } // namespace } // namespace android::compositionengine - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index bac894a6dc..ee4f331b23 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -45,9 +45,13 @@ public: MOCK_CONST_METHOD1(hasCapability, bool(hal::Capability)); MOCK_CONST_METHOD2(hasDisplayCapability, bool(HalDisplayId, hal::DisplayCapability)); - MOCK_METHOD3(allocateVirtualDisplay, - std::optional(uint32_t, uint32_t, ui::PixelFormat*)); + MOCK_CONST_METHOD0(getMaxVirtualDisplayCount, size_t()); + MOCK_CONST_METHOD0(getMaxVirtualDisplayDimension, size_t()); + MOCK_METHOD4(allocateVirtualDisplay, + bool(HalVirtualDisplayId, ui::Size, ui::PixelFormat*, + std::optional)); MOCK_METHOD2(allocatePhysicalDisplay, void(hal::HWDisplayId, PhysicalDisplayId)); + MOCK_METHOD1(createLayer, HWC2::Layer*(HalDisplayId)); MOCK_METHOD2(destroyLayer, void(HalDisplayId, HWC2::Layer*)); MOCK_METHOD3(getDeviceCompositionChanges, diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index bf249cdb25..33c25631bb 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -103,15 +103,21 @@ public: bool needsFiltering() const; ui::LayerStack getLayerStack() const; - // Returns the physical ID of this display. This function asserts the ID is physical and it - // shouldn't be called for other display types, e.g. virtual. + DisplayId getId() const; + + // Shorthand to upcast the ID of a display whose type is known as a precondition. PhysicalDisplayId getPhysicalId() const { - const auto displayIdOpt = PhysicalDisplayId::tryCast(getId()); - LOG_FATAL_IF(!displayIdOpt); - return *displayIdOpt; + const auto id = PhysicalDisplayId::tryCast(getId()); + LOG_FATAL_IF(!id); + return *id; + } + + VirtualDisplayId getVirtualId() const { + const auto id = VirtualDisplayId::tryCast(getId()); + LOG_FATAL_IF(!id); + return *id; } - DisplayId getId() const; const wp& getDisplayToken() const { return mDisplayToken; } int32_t getSequenceId() const { return mSequenceId; } diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index 1cbcf592db..caf0294a56 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -211,9 +211,8 @@ uint32_t Composer::getMaxVirtualDisplayCount() return unwrapRet(ret, 0); } -Error Composer::createVirtualDisplay(uint32_t width, uint32_t height, - PixelFormat* format, Display* outDisplay) -{ +Error Composer::createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format, + std::optional, Display* outDisplay) { const uint32_t bufferSlotCount = 1; Error error = kDefaultError; if (mClient_2_2) { diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 0619b8c444..b525e63c66 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -18,6 +18,7 @@ #define ANDROID_SF_COMPOSER_HAL_H #include +#include #include #include #include @@ -94,8 +95,8 @@ public: virtual Error executeCommands() = 0; virtual uint32_t getMaxVirtualDisplayCount() = 0; - virtual Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format, - Display* outDisplay) = 0; + virtual Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat*, + std::optional mirror, Display* outDisplay) = 0; virtual Error destroyVirtualDisplay(Display display) = 0; virtual Error acceptDisplayChanges(Display display) = 0; @@ -341,7 +342,7 @@ public: uint32_t getMaxVirtualDisplayCount() override; Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format, - Display* outDisplay) override; + std::optional mirror, Display* outDisplay) override; Error destroyVirtualDisplay(Display display) override; Error acceptDisplayChanges(Display display) override; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index b73d0320c3..97cbd0793e 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -38,7 +38,6 @@ #include #include "../Layer.h" // needed only for debugging -#include "../SurfaceFlinger.h" #include "../SurfaceFlingerProperties.h" #include "ComposerHal.h" #include "HWC2.h" @@ -145,8 +144,9 @@ namespace impl { HWComposer::HWComposer(std::unique_ptr composer) : mComposer(std::move(composer)), + mMaxVirtualDisplayDimension(static_cast(sysprop::max_virtual_display_dimension(0))), mUpdateDeviceProductInfoOnHotplugReconnect( - android::sysprop::update_device_product_info_on_hotplug_reconnect(false)) {} + sysprop::update_device_product_info_on_hotplug_reconnect(false)) {} HWComposer::HWComposer(const std::string& composerServiceName) : HWComposer(std::make_unique(composerServiceName)) {} @@ -243,38 +243,49 @@ bool HWComposer::onVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp) { return true; } -std::optional HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height, - ui::PixelFormat* format) { - if (SurfaceFlinger::maxVirtualDisplaySize != 0 && - (width > SurfaceFlinger::maxVirtualDisplaySize || - height > SurfaceFlinger::maxVirtualDisplaySize)) { - ALOGE("%s: Display size %ux%u exceeds maximum dimension of %" PRIu64, __FUNCTION__, width, - height, SurfaceFlinger::maxVirtualDisplaySize); - return {}; +size_t HWComposer::getMaxVirtualDisplayCount() const { + return mComposer->getMaxVirtualDisplayCount(); +} + +size_t HWComposer::getMaxVirtualDisplayDimension() const { + return mMaxVirtualDisplayDimension; +} + +bool HWComposer::allocateVirtualDisplay(HalVirtualDisplayId displayId, ui::Size resolution, + ui::PixelFormat* format, + std::optional mirror) { + if (!resolution.isValid()) { + ALOGE("%s: Invalid resolution %dx%d", __func__, resolution.width, resolution.height); + return false; } - const auto displayId = mVirtualIdGenerator.nextId(); - if (!displayId) { - ALOGE("%s: No remaining virtual displays", __FUNCTION__); - return {}; + const uint32_t width = static_cast(resolution.width); + const uint32_t height = static_cast(resolution.height); + + if (mMaxVirtualDisplayDimension > 0 && + (width > mMaxVirtualDisplayDimension || height > mMaxVirtualDisplayDimension)) { + ALOGE("%s: Resolution %ux%u exceeds maximum dimension %zu", __func__, width, height, + mMaxVirtualDisplayDimension); + return false; } - hal::HWDisplayId hwcDisplayId = 0; - const auto error = static_cast( - mComposer->createVirtualDisplay(width, height, format, &hwcDisplayId)); - if (error != hal::Error::NONE) { - ALOGE("%s: Failed to create HWC virtual display", __FUNCTION__); - mVirtualIdGenerator.markUnused(*displayId); - return {}; + std::optional hwcMirrorId; + if (mirror) { + hwcMirrorId = fromPhysicalDisplayId(*mirror); } + hal::HWDisplayId hwcDisplayId; + const auto error = static_cast( + mComposer->createVirtualDisplay(width, height, format, hwcMirrorId, &hwcDisplayId)); + RETURN_IF_HWC_ERROR_FOR("createVirtualDisplay", error, displayId, false); + auto display = std::make_unique(*mComposer.get(), mCapabilities, hwcDisplayId, hal::DisplayType::VIRTUAL); display->setConnected(true); - auto& displayData = mDisplayData[*displayId]; + auto& displayData = mDisplayData[displayId]; displayData.hwcDisplay = std::move(display); displayData.isVirtual = true; - return displayId; + return true; } void HWComposer::allocatePhysicalDisplay(hal::HWDisplayId hwcDisplayId, @@ -666,13 +677,6 @@ status_t HWComposer::setColorTransform(HalDisplayId displayId, const mat4& trans void HWComposer::disconnectDisplay(HalDisplayId displayId) { RETURN_IF_INVALID_DISPLAY(displayId); auto& displayData = mDisplayData[displayId]; - - // If this was a virtual display, add its slot back for reuse by future - // virtual displays - if (displayData.isVirtual) { - mVirtualIdGenerator.markUnused(*HalVirtualDisplayId::tryCast(displayId)); - } - const auto hwcDisplayId = displayData.hwcDisplay->getId(); // TODO(b/74619554): Select internal/external display from remaining displays. @@ -979,10 +983,6 @@ void HWComposer::loadLayerMetadataSupport() { } } -uint32_t HWComposer::getMaxVirtualDisplayCount() const { - return mComposer->getMaxVirtualDisplayCount(); -} - } // namespace impl } // namespace android diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index f532e50df0..1f81b8db90 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -39,7 +39,6 @@ #include #include -#include "DisplayIdGenerator.h" #include "DisplayIdentification.h" #include "DisplayMode.h" #include "HWC2.h" @@ -109,9 +108,16 @@ public: virtual bool hasCapability(hal::Capability) const = 0; virtual bool hasDisplayCapability(HalDisplayId, hal::DisplayCapability) const = 0; - // Attempts to allocate a virtual display and returns its ID if created on the HWC device. - virtual std::optional allocateVirtualDisplay(uint32_t width, uint32_t height, - ui::PixelFormat*) = 0; + virtual size_t getMaxVirtualDisplayCount() const = 0; + virtual size_t getMaxVirtualDisplayDimension() const = 0; + + // Attempts to allocate a virtual display on the HWC. The maximum number of virtual displays + // supported by the HWC can be queried in advance, but allocation may fail for other reasons. + // For virtualized compositors, the PhysicalDisplayId is a hint that this virtual display is + // a mirror of a physical display, and that the screen should be captured by the host rather + // than guest compositor. + virtual bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*, + std::optional mirror) = 0; virtual void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId) = 0; @@ -254,9 +260,11 @@ public: bool hasCapability(hal::Capability) const override; bool hasDisplayCapability(HalDisplayId, hal::DisplayCapability) const override; - // Attempts to allocate a virtual display and returns its ID if created on the HWC device. - std::optional allocateVirtualDisplay(uint32_t width, uint32_t height, - ui::PixelFormat*) override; + size_t getMaxVirtualDisplayCount() const override; + size_t getMaxVirtualDisplayDimension() const override; + + bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*, + std::optional) override; // Called from SurfaceFlinger, when the state for a new physical display needs to be recreated. void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId) override; @@ -402,7 +410,6 @@ private: void loadCapabilities(); void loadLayerMetadataSupport(); - uint32_t getMaxVirtualDisplayCount() const; std::unordered_map mDisplayData; @@ -416,8 +423,7 @@ private: std::optional mExternalHwcDisplayId; bool mHasMultiDisplaySupport = false; - RandomDisplayIdGenerator mVirtualIdGenerator{getMaxVirtualDisplayCount()}; - + const size_t mMaxVirtualDisplayDimension; const bool mUpdateDeviceProductInfoOnHotplugReconnect; }; diff --git a/services/surfaceflinger/DisplayIdGenerator.h b/services/surfaceflinger/DisplayIdGenerator.h index e7c69a8094..9791a2504a 100644 --- a/services/surfaceflinger/DisplayIdGenerator.h +++ b/services/surfaceflinger/DisplayIdGenerator.h @@ -27,23 +27,16 @@ namespace android { -template +// Generates pseudo-random IDs of type GpuVirtualDisplayId or HalVirtualDisplayId. +template class DisplayIdGenerator { public: - virtual std::optional nextId() = 0; - virtual void markUnused(T id) = 0; - -protected: - ~DisplayIdGenerator() {} -}; - -template -class RandomDisplayIdGenerator final : public DisplayIdGenerator { -public: - explicit RandomDisplayIdGenerator(size_t maxIdsCount = std::numeric_limits::max()) + explicit DisplayIdGenerator(size_t maxIdsCount = std::numeric_limits::max()) : mMaxIdsCount(maxIdsCount) {} - std::optional nextId() override { + bool inUse() const { return !mUsedIds.empty(); } + + std::optional generateId() { if (mUsedIds.size() >= mMaxIdsCount) { return std::nullopt; } @@ -51,8 +44,7 @@ public: constexpr int kMaxAttempts = 1000; for (int attempts = 0; attempts < kMaxAttempts; attempts++) { - const auto baseId = mDistribution(mGenerator); - const T id(baseId); + const Id id{mDistribution(mGenerator)}; if (mUsedIds.count(id) == 0) { mUsedIds.insert(id); return id; @@ -62,14 +54,18 @@ public: LOG_ALWAYS_FATAL("Couldn't generate ID after %d attempts", kMaxAttempts); } - void markUnused(T id) override { mUsedIds.erase(id); } + void releaseId(Id id) { mUsedIds.erase(id); } private: const size_t mMaxIdsCount; - std::unordered_set mUsedIds; + std::unordered_set mUsedIds; + + // Pseudo-random with random seed, in contrast to physical display IDs, which are stable + // across reboots. The only ISurfaceComposer exposure for these IDs is a restricted API + // for screencap, so there is little benefit in making them unpredictable. std::default_random_engine mGenerator{std::random_device()()}; - std::uniform_int_distribution mDistribution; + std::uniform_int_distribution mDistribution; }; -} // namespace android \ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4b0bdcb985..377e68553e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -294,7 +294,6 @@ const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled // --------------------------------------------------------------------------- int64_t SurfaceFlinger::dispSyncPresentTimeOffset; bool SurfaceFlinger::useHwcForRgbToYuv; -uint64_t SurfaceFlinger::maxVirtualDisplaySize; bool SurfaceFlinger::hasSyncFramework; int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers; uint32_t SurfaceFlinger::maxGraphicsWidth; @@ -356,8 +355,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI useHwcForRgbToYuv = force_hwc_copy_for_virtual_displays(false); - maxVirtualDisplaySize = max_virtual_display_dimension(0); - maxFrameBufferAcquiredBuffers = max_frame_buffer_acquired_buffers(2); maxGraphicsWidth = std::max(max_graphics_width(0), 0); @@ -433,10 +430,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI ALOGI_IF(mPropagateBackpressureClientComposition, "Enabling backpressure propagation for Client Composition"); - property_get("debug.sf.enable_hwc_vds", value, "0"); - mUseHwcVirtualDisplays = atoi(value); - ALOGI_IF(mUseHwcVirtualDisplays, "Enabling HWC virtual displays"); - property_get("ro.surface_flinger.supports_background_blur", value, "0"); bool supportsBlurs = atoi(value); mSupportsBlur = supportsBlurs; @@ -574,6 +567,59 @@ void SurfaceFlinger::destroyDisplay(const sp& displayToken) { setTransactionFlags(eDisplayTransactionNeeded); } +void SurfaceFlinger::enableHalVirtualDisplays(bool enable) { + auto& generator = mVirtualDisplayIdGenerators.hal; + if (!generator && enable) { + ALOGI("Enabling HAL virtual displays"); + generator.emplace(getHwComposer().getMaxVirtualDisplayCount()); + } else if (generator && !enable) { + ALOGW_IF(generator->inUse(), "Disabling HAL virtual displays while in use"); + generator.reset(); + } +} + +VirtualDisplayId SurfaceFlinger::acquireVirtualDisplay(ui::Size resolution, ui::PixelFormat format, + ui::LayerStack layerStack) { + if (auto& generator = mVirtualDisplayIdGenerators.hal) { + if (const auto id = generator->generateId()) { + std::optional mirror; + + if (const auto display = findDisplay([layerStack](const auto& display) { + return !display.isVirtual() && display.getLayerStack() == layerStack; + })) { + mirror = display->getPhysicalId(); + } + + if (getHwComposer().allocateVirtualDisplay(*id, resolution, &format, mirror)) { + return *id; + } + + generator->releaseId(*id); + } else { + ALOGW("%s: Exhausted HAL virtual displays", __func__); + } + + ALOGW("%s: Falling back to GPU virtual display", __func__); + } + + const auto id = mVirtualDisplayIdGenerators.gpu.generateId(); + LOG_ALWAYS_FATAL_IF(!id, "Failed to generate ID for GPU virtual display"); + return *id; +} + +void SurfaceFlinger::releaseVirtualDisplay(VirtualDisplayId displayId) { + if (const auto id = HalVirtualDisplayId::tryCast(displayId)) { + if (auto& generator = mVirtualDisplayIdGenerators.hal) { + generator->releaseId(*id); + } + return; + } + + const auto id = GpuVirtualDisplayId::tryCast(displayId); + LOG_ALWAYS_FATAL_IF(!id); + mVirtualDisplayIdGenerators.gpu.releaseId(*id); +} + std::vector SurfaceFlinger::getPhysicalDisplayIds() const { Mutex::Autolock lock(mStateLock); @@ -734,6 +780,11 @@ void SurfaceFlinger::init() { mCompositionEngine->setHwComposer(getFactory().createHWComposer(mHwcServiceName)); mCompositionEngine->getHwComposer().setConfiguration(this, getBE().mComposerSequenceId); ClientCache::getInstance().setRenderEngine(&getRenderEngine()); + + if (base::GetBoolProperty("debug.sf.enable_hwc_vds"s, false)) { + enableHalVirtualDisplays(true); + } + // Process any initial hotplug and resulting display changes. processDisplayHotplugEventsLocked(); const auto display = getDefaultDisplayDeviceLocked(); @@ -2625,10 +2676,10 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status); status = state.surface->query(NATIVE_WINDOW_HEIGHT, &resolution.height); ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status); - int intPixelFormat; - status = state.surface->query(NATIVE_WINDOW_FORMAT, &intPixelFormat); + int format; + status = state.surface->query(NATIVE_WINDOW_FORMAT, &format); ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status); - pixelFormat = static_cast(intPixelFormat); + pixelFormat = static_cast(format); } else { // Virtual displays without a surface are dormant: // they have external state (layer stack, projection, @@ -2638,17 +2689,18 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, compositionengine::DisplayCreationArgsBuilder builder; if (const auto& physical = state.physical) { - builder.setPhysical({physical->id, physical->type}); + builder.setId(physical->id); + builder.setConnectionType(physical->type); + } else { + builder.setId(acquireVirtualDisplay(resolution, pixelFormat, state.layerStack)); } + builder.setPixels(resolution); - builder.setPixelFormat(pixelFormat); builder.setIsSecure(state.isSecure); builder.setLayerStackId(state.layerStack); builder.setPowerAdvisor(&mPowerAdvisor); - builder.setUseHwcVirtualDisplays(mUseHwcVirtualDisplays); - builder.setGpuVirtualDisplayIdGenerator(mGpuVirtualDisplayIdGenerator); builder.setName(state.displayName); - const auto compositionDisplay = getCompositionEngine().createDisplay(builder.build()); + auto compositionDisplay = getCompositionEngine().createDisplay(builder.build()); compositionDisplay->setLayerCachingEnabled(mLayerCachingEnabled); sp displaySurface; @@ -2657,33 +2709,30 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, sp bqConsumer; getFactory().createBufferQueue(&bqProducer, &bqConsumer, /*consumerIsSurfaceFlinger =*/false); - DisplayId displayId = compositionDisplay->getId(); - if (state.isVirtual()) { - const auto virtualId = VirtualDisplayId::tryCast(displayId); - LOG_FATAL_IF(!virtualId); - sp vds = - new VirtualDisplaySurface(getHwComposer(), *virtualId, state.surface, bqProducer, - bqConsumer, state.displayName); - - displaySurface = vds; - producer = vds; + const auto displayId = VirtualDisplayId::tryCast(compositionDisplay->getId()); + LOG_FATAL_IF(!displayId); + auto surface = sp::make(getHwComposer(), *displayId, state.surface, + bqProducer, bqConsumer, state.displayName); + displaySurface = surface; + producer = std::move(surface); } else { ALOGE_IF(state.surface != nullptr, "adding a supported display, but rendering " "surface is provided (%p), ignoring it", state.surface.get()); - const auto physicalId = PhysicalDisplayId::tryCast(displayId); - LOG_FATAL_IF(!physicalId); - displaySurface = new FramebufferSurface(getHwComposer(), *physicalId, bqConsumer, - state.physical->activeMode->getSize(), - ui::Size(maxGraphicsWidth, maxGraphicsHeight)); + const auto displayId = PhysicalDisplayId::tryCast(compositionDisplay->getId()); + LOG_FATAL_IF(!displayId); + displaySurface = + sp::make(getHwComposer(), *displayId, bqConsumer, + state.physical->activeMode->getSize(), + ui::Size(maxGraphicsWidth, maxGraphicsHeight)); producer = bqProducer; } LOG_FATAL_IF(!displaySurface); - const auto display = setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state, - displaySurface, producer); + const auto display = setupNewDisplayDeviceInternal(displayToken, std::move(compositionDisplay), + state, displaySurface, producer); mDisplays.emplace(displayToken, display); if (!state.isVirtual()) { dispatchDisplayHotplugEvent(display->getPhysicalId(), true); @@ -2699,7 +2748,10 @@ void SurfaceFlinger::processDisplayRemoved(const wp& displayToken) { auto display = getDisplayDeviceLocked(displayToken); if (display) { display->disconnect(); - if (!display->isVirtual()) { + + if (display->isVirtual()) { + releaseVirtualDisplay(display->getVirtualId()); + } else { dispatchDisplayHotplugEvent(display->getPhysicalId(), false); } } @@ -2728,17 +2780,26 @@ void SurfaceFlinger::processDisplayChanged(const wp& displayToken, const DisplayDeviceState& drawingState) { const sp currentBinder = IInterface::asBinder(currentState.surface); const sp drawingBinder = IInterface::asBinder(drawingState.surface); + + // Recreate the DisplayDevice if the surface or sequence ID changed. if (currentBinder != drawingBinder || currentState.sequenceId != drawingState.sequenceId) { - // changing the surface is like destroying and recreating the DisplayDevice getRenderEngine().cleanFramebufferCache(); + if (const auto display = getDisplayDeviceLocked(displayToken)) { display->disconnect(); + if (display->isVirtual()) { + releaseVirtualDisplay(display->getVirtualId()); + } } + mDisplays.erase(displayToken); + if (const auto& physical = currentState.physical) { getHwComposer().allocatePhysicalDisplay(physical->hwcDisplayId, physical->id); } + processDisplayAdded(displayToken, currentState); + if (currentState.physical) { const auto display = getDisplayDeviceLocked(displayToken); setPowerModeInternal(display, hal::PowerMode::ON); @@ -4605,7 +4666,8 @@ void SurfaceFlinger::appendSfConfigString(std::string& result) const { StringAppendF(&result, " PRESENT_TIME_OFFSET=%" PRId64, dispSyncPresentTimeOffset); StringAppendF(&result, " FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv); - StringAppendF(&result, " MAX_VIRT_DISPLAY_DIM=%" PRIu64, maxVirtualDisplaySize); + StringAppendF(&result, " MAX_VIRT_DISPLAY_DIM=%zu", + getHwComposer().getMaxVirtualDisplayDimension()); StringAppendF(&result, " RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !hasSyncFramework); StringAppendF(&result, " NUM_FRAMEBUFFER_SURFACE_BUFFERS=%" PRId64, maxFrameBufferAcquiredBuffers); @@ -5363,8 +5425,8 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r return NO_ERROR; } case 1021: { // Disable HWC virtual displays - n = data.readInt32(); - mUseHwcVirtualDisplays = !n; + const bool enable = data.readInt32() != 0; + static_cast(schedule([this, enable] { enableHalVirtualDisplays(enable); })); return NO_ERROR; } case 1022: { // Set saturation boost diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 4aa047a1b2..b46bd9aed8 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -228,10 +228,6 @@ public: // GL composition. static bool useHwcForRgbToYuv; - // Maximum dimension supported by HWC for virtual display. - // Equal to min(max_height, max_width). - static uint64_t maxVirtualDisplaySize; - // Controls the number of buffers SurfaceFlinger will allocate for use in // FramebufferSurface static int64_t maxFrameBufferAcquiredBuffers; @@ -1084,6 +1080,14 @@ private: return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt; } + // Toggles use of HAL/GPU virtual displays. + void enableHalVirtualDisplays(bool); + + // Virtual display lifecycle for ID generation and HAL allocation. + VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat, ui::LayerStack) + REQUIRES(mStateLock); + void releaseVirtualDisplay(VirtualDisplayId); + /* * Debugging & dumpsys */ @@ -1236,7 +1240,10 @@ private: std::unordered_map> mPhysicalDisplayTokens GUARDED_BY(mStateLock); - RandomDisplayIdGenerator mGpuVirtualDisplayIdGenerator; + struct { + DisplayIdGenerator gpu; + std::optional> hal; + } mVirtualDisplayIdGenerators; std::unordered_map> mLayersByLocalBinderToken GUARDED_BY(mStateLock); @@ -1259,7 +1266,7 @@ private: const std::shared_ptr mTimeStats; const std::unique_ptr mFrameTracer; const std::unique_ptr mFrameTimeline; - bool mUseHwcVirtualDisplays = false; + // If blurs should be enabled on this device. bool mSupportsBlur = false; // Disable blurs, for debugging diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index e42cf47657..fca3bfc242 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -105,7 +105,9 @@ public: mFlinger.setupRenderEngine(std::unique_ptr(mRenderEngine)); mFlinger.setupTimeStats(std::shared_ptr(mTimeStats)); - setupComposer(0); + + mComposer = new Hwc2::mock::Composer(); + mFlinger.setupComposer(std::unique_ptr(mComposer)); } ~CompositionTest() { @@ -114,14 +116,6 @@ public: ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } - void setupComposer(int virtualDisplayCount) { - mComposer = new Hwc2::mock::Composer(); - EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount)); - mFlinger.setupComposer(std::unique_ptr(mComposer)); - - Mock::VerifyAndClear(mComposer); - } - void setupScheduler() { auto eventThread = std::make_unique(); auto sfEventThread = std::make_unique(); @@ -289,16 +283,16 @@ struct BaseDisplayVariant { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); - auto ceDisplayArgs = - compositionengine::DisplayCreationArgsBuilder() - .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal}) - .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) - .setIsSecure(Derived::IS_SECURE) - .setLayerStackId(DEFAULT_LAYER_STACK) - .setPowerAdvisor(&test->mPowerAdvisor) - .setName(std::string("Injected display for ") + - test_info->test_case_name() + "." + test_info->name()) - .build(); + auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() + .setId(DEFAULT_DISPLAY_ID) + .setConnectionType(ui::DisplayConnectionType::Internal) + .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) + .setIsSecure(Derived::IS_SECURE) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&test->mPowerAdvisor) + .setName(std::string("Injected display for ") + + test_info->test_case_name() + "." + test_info->name()) + .build(); auto compositionDisplay = compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), diff --git a/services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp index 77a3e1449f..8d4a023615 100644 --- a/services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp @@ -14,76 +14,68 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wextra" - #include +#include +#include +#include #include -#include #include "DisplayIdGenerator.h" namespace android { -template -void testNextId(DisplayIdGenerator& generator) { - constexpr int kNumIds = 5; - std::vector ids; - for (int i = 0; i < kNumIds; i++) { - const auto id = generator.nextId(); - ASSERT_TRUE(id); - ids.push_back(*id); - } +template +void testGenerateId() { + DisplayIdGenerator generator; + + std::vector> ids; + std::generate_n(std::back_inserter(ids), 10, [&] { return generator.generateId(); }); // All IDs should be different. - for (size_t i = 0; i < kNumIds; i++) { - for (size_t j = i + 1; j < kNumIds; j++) { - EXPECT_NE(ids[i], ids[j]); + for (auto it = ids.begin(); it != ids.end(); ++it) { + EXPECT_TRUE(*it); + + for (auto dup = it + 1; dup != ids.end(); ++dup) { + EXPECT_NE(*it, *dup); } } } -TEST(DisplayIdGeneratorTest, nextIdGpuVirtual) { - RandomDisplayIdGenerator generator; - testNextId(generator); +TEST(DisplayIdGeneratorTest, generateGpuVirtualDisplayId) { + testGenerateId(); } -TEST(DisplayIdGeneratorTest, nextIdHalVirtual) { - RandomDisplayIdGenerator generator; - testNextId(generator); +TEST(DisplayIdGeneratorTest, generateHalVirtualDisplayId) { + testGenerateId(); } -TEST(DisplayIdGeneratorTest, markUnused) { +TEST(DisplayIdGeneratorTest, releaseId) { constexpr size_t kMaxIdsCount = 5; - RandomDisplayIdGenerator generator(kMaxIdsCount); + DisplayIdGenerator generator(kMaxIdsCount); - const auto id = generator.nextId(); + const auto id = generator.generateId(); EXPECT_TRUE(id); - for (int i = 1; i < kMaxIdsCount; i++) { - EXPECT_TRUE(generator.nextId()); + for (size_t i = 1; i < kMaxIdsCount; i++) { + EXPECT_TRUE(generator.generateId()); } - EXPECT_FALSE(generator.nextId()); + EXPECT_FALSE(generator.generateId()); - generator.markUnused(*id); - EXPECT_TRUE(generator.nextId()); + generator.releaseId(*id); + EXPECT_TRUE(generator.generateId()); } TEST(DisplayIdGeneratorTest, maxIdsCount) { constexpr size_t kMaxIdsCount = 5; - RandomDisplayIdGenerator generator(kMaxIdsCount); + DisplayIdGenerator generator(kMaxIdsCount); - for (int i = 0; i < kMaxIdsCount; i++) { - EXPECT_TRUE(generator.nextId()); + for (size_t i = 0; i < kMaxIdsCount; i++) { + EXPECT_TRUE(generator.generateId()); } - EXPECT_FALSE(generator.nextId()); + EXPECT_FALSE(generator.generateId()); } } // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 359e555e92..60b0f5334c 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -41,9 +41,6 @@ DisplayTransactionTest::DisplayTransactionTest() { mFlinger.mutableUseColorManagement() = false; mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged; - // Default to using HWC virtual displays - mFlinger.mutableUseHwcVirtualDisplays() = true; - mFlinger.setCreateBufferQueueFunction([](auto, auto, auto) { ADD_FAILURE() << "Unexpected request to create a buffer queue."; }); @@ -85,10 +82,17 @@ void DisplayTransactionTest::injectMockScheduler() { } void DisplayTransactionTest::injectMockComposer(int virtualDisplayCount) { + if (mComposer) { + // If reinjecting, disable first to prevent the enable below from being a no-op. + mFlinger.enableHalVirtualDisplays(false); + } + mComposer = new Hwc2::mock::Composer(); - EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount)); mFlinger.setupComposer(std::unique_ptr(mComposer)); + EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount)); + mFlinger.enableHalVirtualDisplays(true); + Mock::VerifyAndClear(mComposer); } @@ -135,18 +139,21 @@ sp DisplayTransactionTest::injectDefaultInternalDisplay( EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)); EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(AnyNumber()); - auto compositionDisplay = compositionengine::impl:: - createDisplay(mFlinger.getCompositionEngine(), - compositionengine::DisplayCreationArgsBuilder() - .setPhysical( - {DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal}) - .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) - .setPowerAdvisor(&mPowerAdvisor) - .build()); - - auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay, - ui::DisplayConnectionType::Internal, - DEFAULT_DISPLAY_HWC_DISPLAY_ID, true /* isPrimary */); + constexpr auto kConnectionType = ui::DisplayConnectionType::Internal; + constexpr bool kIsPrimary = true; + + auto compositionDisplay = + compositionengine::impl::createDisplay(mFlinger.getCompositionEngine(), + compositionengine::DisplayCreationArgsBuilder() + .setId(DEFAULT_DISPLAY_ID) + .setConnectionType(kConnectionType) + .setPixels({DEFAULT_DISPLAY_WIDTH, + DEFAULT_DISPLAY_HEIGHT}) + .setPowerAdvisor(&mPowerAdvisor) + .build()); + + auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay, kConnectionType, + DEFAULT_DISPLAY_HWC_DISPLAY_ID, kIsPrimary); injector.setNativeWindow(mNativeWindow); if (injectExtra) { diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index d68fff6345..6ce281d403 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -263,40 +263,23 @@ struct DisplayVariant { static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) { auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder(); - if (auto displayId = PhysicalDisplayId::tryCast(DISPLAY_ID::get())) { - ceDisplayArgs.setPhysical({*displayId, ui::DisplayConnectionType::Internal}); - } else { - // We turn off the use of HwcVirtualDisplays, to prevent Composition Engine - // from calling into HWComposer. This way all virtual displays will get - // a GpuVirtualDisplayId, even if we are in the HwcVirtualDisplayVariant. - // In this case we later override it by calling display.setDisplayIdForTesting(). - ceDisplayArgs.setUseHwcVirtualDisplays(false); - - GpuVirtualDisplayId desiredDisplayId = GpuVirtualDisplayId::tryCast(DISPLAY_ID::get()) - .value_or(GpuVirtualDisplayId(0)); - - ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId()) - .WillByDefault(Return(desiredDisplayId)); + ceDisplayArgs.setId(DISPLAY_ID::get()) + .setPixels({WIDTH, HEIGHT}) + .setPowerAdvisor(&test->mPowerAdvisor); - auto& generator = test->mFlinger.gpuVirtualDisplayIdGenerator(); - ceDisplayArgs.setGpuVirtualDisplayIdGenerator(generator); + const auto connectionType = CONNECTION_TYPE::value; + if (connectionType) { + ceDisplayArgs.setConnectionType(*connectionType); } - ceDisplayArgs.setPixels({WIDTH, HEIGHT}).setPowerAdvisor(&test->mPowerAdvisor); auto compositionDisplay = compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), ceDisplayArgs.build()); - if (HalVirtualDisplayId::tryCast(DISPLAY_ID::get())) { - // CompositionEngine has assigned a placeholder GpuVirtualDisplayId and we need to - // override it with the correct HalVirtualDisplayId. - compositionDisplay->setDisplayIdForTesting(DISPLAY_ID::get()); - } - auto injector = TestableSurfaceFlinger::FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay, - CONNECTION_TYPE::value, + connectionType, HWC_DISPLAY_ID_OPT::value, static_cast(PRIMARY)); @@ -404,8 +387,8 @@ struct HwcDisplayVariant { ::testing::UnitTest::GetInstance()->current_test_info(); auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() - .setPhysical({DisplayVariant::DISPLAY_ID::get(), - PhysicalDisplay::CONNECTION_TYPE}) + .setId(DisplayVariant::DISPLAY_ID::get()) + .setConnectionType(PhysicalDisplay::CONNECTION_TYPE) .setPixels({DisplayVariant::WIDTH, DisplayVariant::HEIGHT}) .setIsSecure(static_cast(DisplayVariant::SECURE)) .setPowerAdvisor(&test->mPowerAdvisor) @@ -558,17 +541,13 @@ struct NonHwcVirtualDisplayVariant const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); - ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId()) - .WillByDefault(Return(Base::DISPLAY_ID::get())); - auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() + .setId(Base::DISPLAY_ID::get()) .setPixels({Base::WIDTH, Base::HEIGHT}) .setIsSecure(static_cast(Base::SECURE)) .setPowerAdvisor(&test->mPowerAdvisor) .setName(std::string("Injected display for ") + test_info->test_case_name() + "." + test_info->name()) - .setGpuVirtualDisplayIdGenerator( - test->mFlinger.gpuVirtualDisplayIdGenerator()) .build(); return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), @@ -610,35 +589,22 @@ struct HwcVirtualDisplayVariant const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); - // In order to prevent compostition engine calling into HWComposer, we - // 1. turn off the use of HWC virtual displays, - // 2. provide a GpuVirtualDisplayIdGenerator which always returns some fake ID - // 3. override the ID by calling setDisplayIdForTesting() - - ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId()) - .WillByDefault(Return(GpuVirtualDisplayId(0))); - + const auto displayId = Base::DISPLAY_ID::get(); auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() - .setUseHwcVirtualDisplays(false) + .setId(displayId) .setPixels({Base::WIDTH, Base::HEIGHT}) .setIsSecure(static_cast(Base::SECURE)) .setPowerAdvisor(&test->mPowerAdvisor) .setName(std::string("Injected display for ") + test_info->test_case_name() + "." + test_info->name()) - .setGpuVirtualDisplayIdGenerator( - test->mFlinger.gpuVirtualDisplayIdGenerator()) .build(); auto compositionDisplay = compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), ceDisplayArgs); - compositionDisplay->setDisplayIdForTesting(Base::DISPLAY_ID::get()); // Insert display data so that the HWC thinks it created the virtual display. - if (const auto displayId = Base::DISPLAY_ID::get(); - HalVirtualDisplayId::tryCast(displayId)) { - test->mFlinger.mutableHwcDisplayData().try_emplace(displayId); - } + test->mFlinger.mutableHwcDisplayData().try_emplace(displayId); return compositionDisplay; } @@ -649,8 +615,8 @@ struct HwcVirtualDisplayVariant } static void setupHwcVirtualDisplayCreationCallExpectations(DisplayTransactionTest* test) { - EXPECT_CALL(*test->mComposer, createVirtualDisplay(Base::WIDTH, Base::HEIGHT, _, _)) - .WillOnce(DoAll(SetArgPointee<3>(Self::HWC_DISPLAY_ID), Return(Error::NONE))); + EXPECT_CALL(*test->mComposer, createVirtualDisplay(Base::WIDTH, Base::HEIGHT, _, _, _)) + .WillOnce(DoAll(SetArgPointee<4>(Self::HWC_DISPLAY_ID), Return(Error::NONE))); EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE)); } }; diff --git a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp index dec0ff5df2..010c675574 100644 --- a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp +++ b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp @@ -76,11 +76,9 @@ protected: static constexpr int32_t PRIORITY_UNSET = -1; void setupScheduler(); - void setupComposer(uint32_t virtualDisplayCount); sp createBufferStateLayer(LayerMetadata metadata); TestableSurfaceFlinger mFlinger; - Hwc2::mock::Composer* mComposer = nullptr; mock::FrameTimeline mFrameTimeline = mock::FrameTimeline(std::make_shared(), 0); @@ -103,7 +101,8 @@ FpsReporterTest::FpsReporterTest() { ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); setupScheduler(); - setupComposer(0); + mFlinger.setupComposer(std::make_unique()); + mFpsListener = new TestableFpsListener(); } @@ -145,19 +144,11 @@ void FpsReporterTest::setupScheduler() { std::move(eventThread), std::move(sfEventThread)); } -void FpsReporterTest::setupComposer(uint32_t virtualDisplayCount) { - mComposer = new Hwc2::mock::Composer(); - EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount)); - mFlinger.setupComposer(std::unique_ptr(mComposer)); - - Mock::VerifyAndClear(mComposer); -} - namespace { TEST_F(FpsReporterTest, callsListeners) { mParent = createBufferStateLayer(); - const constexpr int32_t kTaskId = 12; + constexpr int32_t kTaskId = 12; LayerMetadata targetMetadata; targetMetadata.setInt32(METADATA_TASK_ID, kTaskId); mTarget = createBufferStateLayer(targetMetadata); diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp index 6b8217087a..138d5cb7d3 100644 --- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp +++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp @@ -78,7 +78,6 @@ TEST_F(HWComposerSetConfigurationTest, loadsLayerMetadataSupport) { const std::string kMetadata2Name = "com.example.metadata.2"; constexpr bool kMetadata2Mandatory = true; - EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0)); EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector{})); EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_)) .WillOnce(DoAll(SetArgPointee<0>(std::vector{ @@ -101,7 +100,6 @@ TEST_F(HWComposerSetConfigurationTest, loadsLayerMetadataSupport) { } TEST_F(HWComposerSetConfigurationTest, handlesUnsupportedCallToGetLayerGenericMetadataKeys) { - EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0)); EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector{})); EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_)) .WillOnce(Return(hardware::graphics::composer::V2_4::Error::UNSUPPORTED)); @@ -176,4 +174,4 @@ TEST_F(HWComposerLayerGenericMetadataTest, forwardsSupportedMetadata) { } } // namespace -} // namespace android \ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp index 9c6ad06e1d..fd3e564cd9 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp @@ -60,7 +60,6 @@ protected: static constexpr int32_t PRIORITY_UNSET = -1; void setupScheduler(); - void setupComposer(uint32_t virtualDisplayCount); sp createBufferQueueLayer(); sp createBufferStateLayer(); sp createEffectLayer(); @@ -69,7 +68,6 @@ protected: void commitTransaction(Layer* layer); TestableSurfaceFlinger mFlinger; - Hwc2::mock::Composer* mComposer = nullptr; sp mClient; sp mParent; @@ -83,7 +81,7 @@ RefreshRateSelectionTest::RefreshRateSelectionTest() { ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); setupScheduler(); - setupComposer(0); + mFlinger.setupComposer(std::make_unique()); } RefreshRateSelectionTest::~RefreshRateSelectionTest() { @@ -147,14 +145,6 @@ void RefreshRateSelectionTest::setupScheduler() { std::move(eventThread), std::move(sfEventThread)); } -void RefreshRateSelectionTest::setupComposer(uint32_t virtualDisplayCount) { - mComposer = new Hwc2::mock::Composer(); - EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount)); - mFlinger.setupComposer(std::unique_ptr(mComposer)); - - Mock::VerifyAndClear(mComposer); -} - namespace { /* ------------------------------------------------------------------------ * Test cases diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index c088ddc971..46ef75091e 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -118,14 +118,12 @@ protected: SetFrameRateTest(); void setupScheduler(); - void setupComposer(uint32_t virtualDisplayCount); void addChild(sp layer, sp child); void removeChild(sp layer, sp child); void commitTransaction(); TestableSurfaceFlinger mFlinger; - Hwc2::mock::Composer* mComposer = nullptr; mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); std::vector> mLayers; @@ -139,10 +137,11 @@ SetFrameRateTest::SetFrameRateTest() { mFlinger.mutableUseFrameRateApi() = true; setupScheduler(); - setupComposer(0); + mFlinger.setupComposer(std::make_unique()); mFlinger.mutableEventQueue().reset(mMessageQueue); } + void SetFrameRateTest::addChild(sp layer, sp child) { layer.get()->addChild(child.get()); } @@ -184,14 +183,6 @@ void SetFrameRateTest::setupScheduler() { /*hasMultipleModes*/ true); } -void SetFrameRateTest::setupComposer(uint32_t virtualDisplayCount) { - mComposer = new Hwc2::mock::Composer(); - EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount)); - mFlinger.setupComposer(std::unique_ptr(mComposer)); - - Mock::VerifyAndClear(mComposer); -} - namespace { /* ------------------------------------------------------------------------ * Test cases diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index d004b9d9eb..f95b878ec0 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -42,7 +42,6 @@ #include "SurfaceInterceptor.h" #include "TestableScheduler.h" #include "mock/DisplayHardware/MockComposer.h" -#include "mock/MockDisplayIdGenerator.h" #include "mock/MockFrameTimeline.h" #include "mock/MockFrameTracer.h" @@ -185,9 +184,6 @@ public: SurfaceFlinger* flinger() { return mFlinger.get(); } TestableScheduler* scheduler() { return mScheduler; } - mock::DisplayIdGenerator& gpuVirtualDisplayIdGenerator() { - return mGpuVirtualDisplayIdGenerator; - } // Extend this as needed for accessing SurfaceFlinger private (and public) // functions. @@ -308,6 +304,8 @@ public: return mFlinger->destroyDisplay(displayToken); } + void enableHalVirtualDisplays(bool enable) { mFlinger->enableHalVirtualDisplays(enable); } + auto setupNewDisplayDeviceInternal( const wp& displayToken, std::shared_ptr compositionDisplay, @@ -436,7 +434,6 @@ public: auto& mutablePhysicalDisplayTokens() { return mFlinger->mPhysicalDisplayTokens; } auto& mutableTexturePool() { return mFlinger->mTexturePool; } auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; } - auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; } auto& mutablePowerAdvisor() { return mFlinger->mPowerAdvisor; } auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; } @@ -775,7 +772,6 @@ private: surfaceflinger::test::Factory mFactory; sp mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization); TestableScheduler* mScheduler = nullptr; - mock::DisplayIdGenerator mGpuVirtualDisplayIdGenerator; }; } // namespace android diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp index 25001d3890..546bc4a17b 100644 --- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp @@ -45,7 +45,7 @@ public: ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); setupScheduler(); - setupComposer(0); + mFlinger.setupComposer(std::make_unique()); } ~TransactionFrameTracerTest() { @@ -91,17 +91,9 @@ public: std::move(eventThread), std::move(sfEventThread)); } - void setupComposer(uint32_t virtualDisplayCount) { - mComposer = new Hwc2::mock::Composer(); - EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount)); - mFlinger.setupComposer(std::unique_ptr(mComposer)); - - Mock::VerifyAndClear(mComposer); - } - TestableSurfaceFlinger mFlinger; - Hwc2::mock::Composer* mComposer = nullptr; renderengine::mock::RenderEngine mRenderEngine; + FenceToFenceTimeMap fenceFactory; client_cache_t mClientCache; diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp index b7917aa00e..c1123cd6e8 100644 --- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp @@ -45,7 +45,7 @@ public: ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); setupScheduler(); - setupComposer(0); + mFlinger.setupComposer(std::make_unique()); } ~TransactionSurfaceFrameTest() { @@ -91,17 +91,9 @@ public: std::move(eventThread), std::move(sfEventThread)); } - void setupComposer(uint32_t virtualDisplayCount) { - mComposer = new Hwc2::mock::Composer(); - EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount)); - mFlinger.setupComposer(std::unique_ptr(mComposer)); - - Mock::VerifyAndClear(mComposer); - } - TestableSurfaceFlinger mFlinger; - Hwc2::mock::Composer* mComposer = nullptr; renderengine::mock::RenderEngine mRenderEngine; + FenceToFenceTimeMap fenceFactory; client_cache_t mClientCache; diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index 1ba3c0f56e..cb3bd73920 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -54,7 +54,8 @@ public: MOCK_METHOD0(resetCommands, void()); MOCK_METHOD0(executeCommands, Error()); MOCK_METHOD0(getMaxVirtualDisplayCount, uint32_t()); - MOCK_METHOD4(createVirtualDisplay, Error(uint32_t, uint32_t, PixelFormat*, Display*)); + MOCK_METHOD5(createVirtualDisplay, + Error(uint32_t, uint32_t, PixelFormat*, std::optional, Display*)); MOCK_METHOD1(destroyVirtualDisplay, Error(Display)); MOCK_METHOD1(acceptDisplayChanges, Error(Display)); MOCK_METHOD2(createLayer, Error(Display, Layer* outLayer)); diff --git a/services/surfaceflinger/tests/unittests/mock/MockDisplayIdGenerator.h b/services/surfaceflinger/tests/unittests/mock/MockDisplayIdGenerator.h deleted file mode 100644 index cfc37ea8d9..0000000000 --- a/services/surfaceflinger/tests/unittests/mock/MockDisplayIdGenerator.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -#include "DisplayIdGenerator.h" - -namespace android::mock { - -template -class DisplayIdGenerator : public android::DisplayIdGenerator { -public: - // Explicit default instantiation is recommended. - DisplayIdGenerator() = default; - virtual ~DisplayIdGenerator() = default; - - MOCK_METHOD0(nextId, std::optional()); - MOCK_METHOD1(markUnused, void(T)); -}; - -} // namespace android::mock -- cgit v1.2.3-59-g8ed1b From 0deb06ecc8aadcaca8a56e935fe11834d1533272 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Fri, 16 Apr 2021 23:18:31 -0700 Subject: SF: Remove composer sequence IDs Multiple HWC instances are no longer supported since VR was nixed. Also, rename HAL callbacks so their origin is clear. Bug: 182939859 Test: Build Change-Id: Ia09b120dce1a4659a3cbb8927d44da8fba266c54 --- .../CompositionEngine/tests/MockHWComposer.h | 2 +- services/surfaceflinger/DisplayHardware/HWC2.h | 20 ++- .../surfaceflinger/DisplayHardware/HWComposer.cpp | 39 +++-- .../surfaceflinger/DisplayHardware/HWComposer.h | 4 +- services/surfaceflinger/SurfaceFlinger.cpp | 43 ++---- services/surfaceflinger/SurfaceFlinger.h | 25 ++-- services/surfaceflinger/tests/unittests/Android.bp | 2 +- .../tests/unittests/HWComposerTest.cpp | 25 ++-- .../tests/unittests/SurfaceFlinger_HotplugTest.cpp | 113 +++++++++++++++ .../SurfaceFlinger_OnHotplugReceivedTest.cpp | 158 --------------------- .../tests/unittests/TestableSurfaceFlinger.h | 6 +- 11 files changed, 176 insertions(+), 261 deletions(-) create mode 100644 services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp delete mode 100644 services/surfaceflinger/tests/unittests/SurfaceFlinger_OnHotplugReceivedTest.cpp diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index ee4f331b23..fd71d2824a 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -39,7 +39,7 @@ public: HWComposer(); ~HWComposer() override; - MOCK_METHOD2(setConfiguration, void(HWC2::ComposerCallback*, int32_t)); + MOCK_METHOD1(setCallback, void(HWC2::ComposerCallback*)); MOCK_CONST_METHOD3(getDisplayIdentificationData, bool(hal::HWDisplayId, uint8_t*, DisplayIdentificationData*)); MOCK_CONST_METHOD1(hasCapability, bool(hal::Capability)); diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index e7bf286d08..5685c9a889 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -55,20 +55,16 @@ namespace hal = android::hardware::graphics::composer::hal; // Implement this interface to receive hardware composer events. // // These callback functions will generally be called on a hwbinder thread, but -// when first registering the callback the onHotplugReceived() function will +// when first registering the callback the onComposerHalHotplug() function will // immediately be called on the thread calling registerCallback(). -// -// All calls receive a sequenceId, which will be the value that was supplied to -// HWC2::Device::registerCallback(). It's used to help differentiate callbacks -// from different hardware composer instances. struct ComposerCallback { - virtual void onHotplugReceived(int32_t sequenceId, hal::HWDisplayId, hal::Connection) = 0; - virtual void onRefreshReceived(int32_t sequenceId, hal::HWDisplayId) = 0; - virtual void onVsyncReceived(int32_t sequenceId, hal::HWDisplayId, int64_t timestamp, - std::optional) = 0; - virtual void onVsyncPeriodTimingChangedReceived(int32_t sequenceId, hal::HWDisplayId, - const hal::VsyncPeriodChangeTimeline&) = 0; - virtual void onSeamlessPossible(int32_t sequenceId, hal::HWDisplayId) = 0; + virtual void onComposerHalHotplug(hal::HWDisplayId, hal::Connection) = 0; + virtual void onComposerHalRefresh(hal::HWDisplayId) = 0; + virtual void onComposerHalVsync(hal::HWDisplayId, int64_t timestamp, + std::optional) = 0; + virtual void onComposerHalVsyncPeriodTimingChanged(hal::HWDisplayId, + const hal::VsyncPeriodChangeTimeline&) = 0; + virtual void onComposerHalSeamlessPossible(hal::HWDisplayId) = 0; protected: ~ComposerCallback() = default; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 97cbd0793e..c03f7df965 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -82,25 +82,22 @@ using android::HWC2::ComposerCallback; class ComposerCallbackBridge : public hal::IComposerCallback { public: - ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId, - bool vsyncSwitchingSupported) - : mCallback(callback), - mSequenceId(sequenceId), - mVsyncSwitchingSupported(vsyncSwitchingSupported) {} - - Return onHotplug(hal::HWDisplayId display, hal::Connection conn) override { - mCallback->onHotplugReceived(mSequenceId, display, conn); + ComposerCallbackBridge(ComposerCallback* callback, bool vsyncSwitchingSupported) + : mCallback(callback), mVsyncSwitchingSupported(vsyncSwitchingSupported) {} + + Return onHotplug(hal::HWDisplayId display, hal::Connection connection) override { + mCallback->onComposerHalHotplug(display, connection); return Void(); } Return onRefresh(hal::HWDisplayId display) override { - mCallback->onRefreshReceived(mSequenceId, display); + mCallback->onComposerHalRefresh(display); return Void(); } Return onVsync(hal::HWDisplayId display, int64_t timestamp) override { if (!mVsyncSwitchingSupported) { - mCallback->onVsyncReceived(mSequenceId, display, timestamp, std::nullopt); + mCallback->onComposerHalVsync(display, timestamp, std::nullopt); } else { ALOGW("Unexpected onVsync callback on composer >= 2.4, ignoring."); } @@ -110,8 +107,7 @@ public: Return onVsync_2_4(hal::HWDisplayId display, int64_t timestamp, hal::VsyncPeriodNanos vsyncPeriodNanos) override { if (mVsyncSwitchingSupported) { - mCallback->onVsyncReceived(mSequenceId, display, timestamp, - std::make_optional(vsyncPeriodNanos)); + mCallback->onComposerHalVsync(display, timestamp, vsyncPeriodNanos); } else { ALOGW("Unexpected onVsync_2_4 callback on composer <= 2.3, ignoring."); } @@ -119,20 +115,18 @@ public: } Return onVsyncPeriodTimingChanged( - hal::HWDisplayId display, - const hal::VsyncPeriodChangeTimeline& updatedTimeline) override { - mCallback->onVsyncPeriodTimingChangedReceived(mSequenceId, display, updatedTimeline); + hal::HWDisplayId display, const hal::VsyncPeriodChangeTimeline& timeline) override { + mCallback->onComposerHalVsyncPeriodTimingChanged(display, timeline); return Void(); } Return onSeamlessPossible(hal::HWDisplayId display) override { - mCallback->onSeamlessPossible(mSequenceId, display); + mCallback->onComposerHalSeamlessPossible(display); return Void(); } private: - ComposerCallback* mCallback; - const int32_t mSequenceId; + ComposerCallback* const mCallback; const bool mVsyncSwitchingSupported; }; @@ -155,7 +149,7 @@ HWComposer::~HWComposer() { mDisplayData.clear(); } -void HWComposer::setConfiguration(HWC2::ComposerCallback* callback, int32_t sequenceId) { +void HWComposer::setCallback(HWC2::ComposerCallback* callback) { loadCapabilities(); loadLayerMetadataSupport(); @@ -164,10 +158,9 @@ void HWComposer::setConfiguration(HWC2::ComposerCallback* callback, int32_t sequ return; } mRegisteredCallback = true; - sp callbackBridge( - new ComposerCallbackBridge(callback, sequenceId, - mComposer->isVsyncPeriodSwitchSupported())); - mComposer->registerCallback(callbackBridge); + + mComposer->registerCallback( + sp::make(callback, mComposer->isVsyncPeriodSwitchSupported())); } bool HWComposer::getDisplayIdentificationData(hal::HWDisplayId hwcDisplayId, uint8_t* outPort, diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 1f81b8db90..3d462cbbc8 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -100,7 +100,7 @@ public: virtual ~HWComposer(); - virtual void setConfiguration(HWC2::ComposerCallback* callback, int32_t sequenceId) = 0; + virtual void setCallback(HWC2::ComposerCallback*) = 0; virtual bool getDisplayIdentificationData(hal::HWDisplayId, uint8_t* outPort, DisplayIdentificationData* outData) const = 0; @@ -252,7 +252,7 @@ public: ~HWComposer() override; - void setConfiguration(HWC2::ComposerCallback* callback, int32_t sequenceId) override; + void setCallback(HWC2::ComposerCallback*) override; bool getDisplayIdentificationData(hal::HWDisplayId, uint8_t* outPort, DisplayIdentificationData* outData) const override; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 377e68553e..442b4bb934 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -778,7 +778,7 @@ void SurfaceFlinger::init() { .build())); mCompositionEngine->setTimeStats(mTimeStats); mCompositionEngine->setHwComposer(getFactory().createHWComposer(mHwcServiceName)); - mCompositionEngine->getHwComposer().setConfiguration(this, getBE().mComposerSequenceId); + mCompositionEngine->getHwComposer().setCallback(this); ClientCache::getInstance().setRenderEngine(&getRenderEngine()); if (base::GetBoolProperty("debug.sf.enable_hwc_vds"s, false)) { @@ -1638,16 +1638,11 @@ nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const { return 0; } -void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hal::HWDisplayId hwcDisplayId, - int64_t timestamp, - std::optional vsyncPeriod) { - ATRACE_NAME("SF onVsync"); +void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp, + std::optional vsyncPeriod) { + ATRACE_CALL(); Mutex::Autolock lock(mStateLock); - // Ignore any vsyncs from a previous hardware composer. - if (sequenceId != getBE().mComposerSequenceId) { - return; - } if (const auto displayId = getHwComposer().toPhysicalDisplayId(hwcDisplayId)) { auto token = getPhysicalDisplayTokenLocked(*displayId); @@ -1698,16 +1693,11 @@ void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate, setDesiredActiveMode({refreshRate.getModeId(), event}); } -void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hal::HWDisplayId hwcDisplayId, - hal::Connection connection) { - ALOGI("%s(%d, %" PRIu64 ", %s)", __FUNCTION__, sequenceId, hwcDisplayId, +void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, + hal::Connection connection) { + ALOGI("%s(%" PRIu64 ", %s)", __func__, hwcDisplayId, connection == hal::Connection::CONNECTED ? "connected" : "disconnected"); - // Ignore events that do not have the right sequenceId. - if (sequenceId != getBE().mComposerSequenceId) { - return; - } - // Only lock if we're not on the main thread. This function is normally // called on a hwbinder thread, but for the primary display it's called on // the main thread with the state lock already held, so don't attempt to @@ -1724,26 +1714,19 @@ void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hal::HWDisplayId hwcD setTransactionFlags(eDisplayTransactionNeeded); } -void SurfaceFlinger::onVsyncPeriodTimingChangedReceived( - int32_t sequenceId, hal::HWDisplayId /*display*/, - const hal::VsyncPeriodChangeTimeline& updatedTimeline) { +void SurfaceFlinger::onComposerHalVsyncPeriodTimingChanged( + hal::HWDisplayId, const hal::VsyncPeriodChangeTimeline& timeline) { Mutex::Autolock lock(mStateLock); - if (sequenceId != getBE().mComposerSequenceId) { - return; - } - mScheduler->onNewVsyncPeriodChangeTimeline(updatedTimeline); + mScheduler->onNewVsyncPeriodChangeTimeline(timeline); } -void SurfaceFlinger::onSeamlessPossible(int32_t /*sequenceId*/, hal::HWDisplayId /*display*/) { +void SurfaceFlinger::onComposerHalSeamlessPossible(hal::HWDisplayId) { // TODO(b/142753666): use constraints when calling to setActiveModeWithConstraints and // use this callback to know when to retry in case of SEAMLESS_NOT_POSSIBLE. } -void SurfaceFlinger::onRefreshReceived(int sequenceId, hal::HWDisplayId /*hwcDisplayId*/) { +void SurfaceFlinger::onComposerHalRefresh(hal::HWDisplayId) { Mutex::Autolock lock(mStateLock); - if (sequenceId != getBE().mComposerSequenceId) { - return; - } repaintEverythingForHWC(); } @@ -5613,7 +5596,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r Mutex::Autolock lock(mStateLock); hwcId = getHwComposer().getInternalHwcDisplayId(); } - onHotplugReceived(getBE().mComposerSequenceId, *hwcId, hal::Connection::CONNECTED); + onComposerHalHotplug(*hwcId, hal::Connection::CONNECTED); return NO_ERROR; } // Modify the max number of display frames stored within FrameTimeline diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b46bd9aed8..f85a6c6d44 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -169,11 +169,6 @@ struct SurfaceFlingerBE { }; mutable Mutex mBufferingStatsMutex; std::unordered_map mBufferingStats; - - // The composer sequence id is a monotonically increasing integer that we - // use to differentiate callbacks from different hardware composer - // instances. Each hardware composer instance gets a different sequence id. - int32_t mComposerSequenceId = 0; }; class SurfaceFlinger : public BnSurfaceComposer, @@ -706,18 +701,14 @@ private: // Implements RefBase. void onFirstRef() override; - /* - * HWC2::ComposerCallback / HWComposer::EventHandler interface - */ - void onVsyncReceived(int32_t sequenceId, hal::HWDisplayId hwcDisplayId, int64_t timestamp, - std::optional vsyncPeriod) override; - void onHotplugReceived(int32_t sequenceId, hal::HWDisplayId hwcDisplayId, - hal::Connection connection) override; - void onRefreshReceived(int32_t sequenceId, hal::HWDisplayId hwcDisplayId) override; - void onVsyncPeriodTimingChangedReceived( - int32_t sequenceId, hal::HWDisplayId display, - const hal::VsyncPeriodChangeTimeline& updatedTimeline) override; - void onSeamlessPossible(int32_t sequenceId, hal::HWDisplayId display) override; + // HWC2::ComposerCallback overrides: + void onComposerHalVsync(hal::HWDisplayId, int64_t timestamp, + std::optional) override; + void onComposerHalHotplug(hal::HWDisplayId, hal::Connection) override; + void onComposerHalRefresh(hal::HWDisplayId) override; + void onComposerHalVsyncPeriodTimingChanged(hal::HWDisplayId, + const hal::VsyncPeriodChangeTimeline&) override; + void onComposerHalSeamlessPossible(hal::HWDisplayId) override; /* * ISchedulerCallback diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 88fb811b52..de511f3700 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -68,7 +68,7 @@ cc_test { "SurfaceFlinger_GetDisplayNativePrimariesTest.cpp", "SurfaceFlinger_HandleTransactionLockedTest.cpp", "SurfaceFlinger_NotifyPowerBoostTest.cpp", - "SurfaceFlinger_OnHotplugReceivedTest.cpp", + "SurfaceFlinger_HotplugTest.cpp", "SurfaceFlinger_OnInitializeDisplaysTest.cpp", "SurfaceFlinger_SetDisplayStateTest.cpp", "SurfaceFlinger_SetPowerModeInternalTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp index 138d5cb7d3..7d77abcef1 100644 --- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp +++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp @@ -57,22 +57,21 @@ using ::testing::SetArgPointee; using ::testing::StrictMock; struct MockHWC2ComposerCallback final : StrictMock { - MOCK_METHOD3(onHotplugReceived, void(int32_t sequenceId, hal::HWDisplayId, hal::Connection)); - MOCK_METHOD2(onRefreshReceived, void(int32_t sequenceId, hal::HWDisplayId)); - MOCK_METHOD4(onVsyncReceived, - void(int32_t sequenceId, hal::HWDisplayId, int64_t timestamp, - std::optional)); - MOCK_METHOD3(onVsyncPeriodTimingChangedReceived, - void(int32_t sequenceId, hal::HWDisplayId, const hal::VsyncPeriodChangeTimeline&)); - MOCK_METHOD2(onSeamlessPossible, void(int32_t sequenceId, hal::HWDisplayId)); + MOCK_METHOD2(onComposerHalHotplug, void(hal::HWDisplayId, hal::Connection)); + MOCK_METHOD1(onComposerHalRefresh, void(hal::HWDisplayId)); + MOCK_METHOD3(onComposerHalVsync, + void(hal::HWDisplayId, int64_t timestamp, std::optional)); + MOCK_METHOD2(onComposerHalVsyncPeriodTimingChanged, + void(hal::HWDisplayId, const hal::VsyncPeriodChangeTimeline&)); + MOCK_METHOD1(onComposerHalSeamlessPossible, void(hal::HWDisplayId)); }; -struct HWComposerSetConfigurationTest : testing::Test { +struct HWComposerSetCallbackTest : testing::Test { Hwc2::mock::Composer* mHal = new StrictMock(); MockHWC2ComposerCallback mCallback; }; -TEST_F(HWComposerSetConfigurationTest, loadsLayerMetadataSupport) { +TEST_F(HWComposerSetCallbackTest, loadsLayerMetadataSupport) { const std::string kMetadata1Name = "com.example.metadata.1"; constexpr bool kMetadata1Mandatory = false; const std::string kMetadata2Name = "com.example.metadata.2"; @@ -89,7 +88,7 @@ TEST_F(HWComposerSetConfigurationTest, loadsLayerMetadataSupport) { EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported()).WillOnce(Return(false)); impl::HWComposer hwc{std::unique_ptr(mHal)}; - hwc.setConfiguration(&mCallback, 123); + hwc.setCallback(&mCallback); const auto& supported = hwc.getSupportedLayerGenericMetadata(); EXPECT_EQ(2u, supported.size()); @@ -99,7 +98,7 @@ TEST_F(HWComposerSetConfigurationTest, loadsLayerMetadataSupport) { EXPECT_EQ(kMetadata2Mandatory, supported.find(kMetadata2Name)->second); } -TEST_F(HWComposerSetConfigurationTest, handlesUnsupportedCallToGetLayerGenericMetadataKeys) { +TEST_F(HWComposerSetCallbackTest, handlesUnsupportedCallToGetLayerGenericMetadataKeys) { EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector{})); EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_)) .WillOnce(Return(hardware::graphics::composer::V2_4::Error::UNSUPPORTED)); @@ -107,7 +106,7 @@ TEST_F(HWComposerSetConfigurationTest, handlesUnsupportedCallToGetLayerGenericMe EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported()).WillOnce(Return(false)); impl::HWComposer hwc{std::unique_ptr(mHal)}; - hwc.setConfiguration(&mCallback, 123); + hwc.setCallback(&mCallback); const auto& supported = hwc.getSupportedLayerGenericMetadata(); EXPECT_EQ(0u, supported.size()); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp new file mode 100644 index 0000000000..bd89397ef6 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp @@ -0,0 +1,113 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef LOG_TAG +#define LOG_TAG "LibSurfaceFlingerUnittests" + +#include "DisplayTransactionTestHelpers.h" + +namespace android { +namespace { + +class HotplugTest : public DisplayTransactionTest {}; + +TEST_F(HotplugTest, enqueuesEventsForDisplayTransaction) { + constexpr HWDisplayId hwcDisplayId1 = 456; + constexpr HWDisplayId hwcDisplayId2 = 654; + + // -------------------------------------------------------------------- + // Preconditions + + // Set the main thread id so that the current thread does not appear to be + // the main thread. + mFlinger.mutableMainThreadId() = std::thread::id(); + + // -------------------------------------------------------------------- + // Call Expectations + + // We expect invalidate() to be invoked once to trigger display transaction + // processing. + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + // -------------------------------------------------------------------- + // Invocation + + // Simulate two hotplug events (a connect and a disconnect) + mFlinger.onComposerHalHotplug(hwcDisplayId1, Connection::CONNECTED); + mFlinger.onComposerHalHotplug(hwcDisplayId2, Connection::DISCONNECTED); + + // -------------------------------------------------------------------- + // Postconditions + + // The display transaction needed flag should be set. + EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded)); + + // All events should be in the pending event queue. + const auto& pendingEvents = mFlinger.mutablePendingHotplugEvents(); + ASSERT_EQ(2u, pendingEvents.size()); + EXPECT_EQ(hwcDisplayId1, pendingEvents[0].hwcDisplayId); + EXPECT_EQ(Connection::CONNECTED, pendingEvents[0].connection); + EXPECT_EQ(hwcDisplayId2, pendingEvents[1].hwcDisplayId); + EXPECT_EQ(Connection::DISCONNECTED, pendingEvents[1].connection); +} + +TEST_F(HotplugTest, processesEnqueuedEventsIfCalledOnMainThread) { + constexpr HWDisplayId displayId1 = 456; + + // -------------------------------------------------------------------- + // Note: + // -------------------------------------------------------------------- + // This test case is a bit tricky. We want to verify that + // onComposerHalHotplug() calls processDisplayHotplugEventsLocked(), but we + // don't really want to provide coverage for everything the later function + // does as there are specific tests for it. + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Preconditions + + // Set the main thread id so that the current thread does appear to be the + // main thread. + mFlinger.mutableMainThreadId() = std::this_thread::get_id(); + + // -------------------------------------------------------------------- + // Call Expectations + + // We expect invalidate() to be invoked once to trigger display transaction + // processing. + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + // -------------------------------------------------------------------- + // Invocation + + // Simulate a disconnect on a display id that is not connected. This should + // be enqueued by onComposerHalHotplug(), and dequeued by + // processDisplayHotplugEventsLocked(), but then ignored as invalid. + mFlinger.onComposerHalHotplug(displayId1, Connection::DISCONNECTED); + + // -------------------------------------------------------------------- + // Postconditions + + // The display transaction needed flag should be set. + EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded)); + + // There should be no event queued on return, as it should have been + // processed. + EXPECT_TRUE(mFlinger.mutablePendingHotplugEvents().empty()); +} + +} // namespace +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnHotplugReceivedTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnHotplugReceivedTest.cpp deleted file mode 100644 index 42f4cf31ba..0000000000 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnHotplugReceivedTest.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#undef LOG_TAG -#define LOG_TAG "LibSurfaceFlingerUnittests" - -#include "DisplayTransactionTestHelpers.h" - -namespace android { -namespace { - -class OnHotplugReceivedTest : public DisplayTransactionTest {}; - -TEST_F(OnHotplugReceivedTest, hotplugEnqueuesEventsForDisplayTransaction) { - constexpr int currentSequenceId = 123; - constexpr HWDisplayId hwcDisplayId1 = 456; - constexpr HWDisplayId hwcDisplayId2 = 654; - - // -------------------------------------------------------------------- - // Preconditions - - // Set the current sequence id for accepted events - mFlinger.mutableComposerSequenceId() = currentSequenceId; - - // Set the main thread id so that the current thread does not appear to be - // the main thread. - mFlinger.mutableMainThreadId() = std::thread::id(); - - // -------------------------------------------------------------------- - // Call Expectations - - // We expect invalidate() to be invoked once to trigger display transaction - // processing. - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); - - // -------------------------------------------------------------------- - // Invocation - - // Simulate two hotplug events (a connect and a disconnect) - mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId1, Connection::CONNECTED); - mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId2, Connection::DISCONNECTED); - - // -------------------------------------------------------------------- - // Postconditions - - // The display transaction needed flag should be set. - EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded)); - - // All events should be in the pending event queue. - const auto& pendingEvents = mFlinger.mutablePendingHotplugEvents(); - ASSERT_EQ(2u, pendingEvents.size()); - EXPECT_EQ(hwcDisplayId1, pendingEvents[0].hwcDisplayId); - EXPECT_EQ(Connection::CONNECTED, pendingEvents[0].connection); - EXPECT_EQ(hwcDisplayId2, pendingEvents[1].hwcDisplayId); - EXPECT_EQ(Connection::DISCONNECTED, pendingEvents[1].connection); -} - -TEST_F(OnHotplugReceivedTest, hotplugDiscardsUnexpectedEvents) { - constexpr int currentSequenceId = 123; - constexpr int otherSequenceId = 321; - constexpr HWDisplayId displayId = 456; - - // -------------------------------------------------------------------- - // Preconditions - - // Set the current sequence id for accepted events - mFlinger.mutableComposerSequenceId() = currentSequenceId; - - // Set the main thread id so that the current thread does not appear to be - // the main thread. - mFlinger.mutableMainThreadId() = std::thread::id(); - - // -------------------------------------------------------------------- - // Call Expectations - - // We do not expect any calls to invalidate(). - EXPECT_CALL(*mMessageQueue, invalidate()).Times(0); - - // -------------------------------------------------------------------- - // Invocation - - // Call with an unexpected sequence id - mFlinger.onHotplugReceived(otherSequenceId, displayId, Connection::INVALID); - - // -------------------------------------------------------------------- - // Postconditions - - // The display transaction needed flag should not be set - EXPECT_FALSE(hasTransactionFlagSet(eDisplayTransactionNeeded)); - - // There should be no pending events - EXPECT_TRUE(mFlinger.mutablePendingHotplugEvents().empty()); -} - -TEST_F(OnHotplugReceivedTest, hotplugProcessesEnqueuedEventsIfCalledOnMainThread) { - constexpr int currentSequenceId = 123; - constexpr HWDisplayId displayId1 = 456; - - // -------------------------------------------------------------------- - // Note: - // -------------------------------------------------------------------- - // This test case is a bit tricky. We want to verify that - // onHotplugReceived() calls processDisplayHotplugEventsLocked(), but we - // don't really want to provide coverage for everything the later function - // does as there are specific tests for it. - // -------------------------------------------------------------------- - - // -------------------------------------------------------------------- - // Preconditions - - // Set the current sequence id for accepted events - mFlinger.mutableComposerSequenceId() = currentSequenceId; - - // Set the main thread id so that the current thread does appear to be the - // main thread. - mFlinger.mutableMainThreadId() = std::this_thread::get_id(); - - // -------------------------------------------------------------------- - // Call Expectations - - // We expect invalidate() to be invoked once to trigger display transaction - // processing. - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); - - // -------------------------------------------------------------------- - // Invocation - - // Simulate a disconnect on a display id that is not connected. This should - // be enqueued by onHotplugReceived(), and dequeued by - // processDisplayHotplugEventsLocked(), but then ignored as invalid. - mFlinger.onHotplugReceived(currentSequenceId, displayId1, Connection::DISCONNECTED); - - // -------------------------------------------------------------------- - // Postconditions - - // The display transaction needed flag should be set. - EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded)); - - // There should be no event queued on return, as it should have been - // processed. - EXPECT_TRUE(mFlinger.mutablePendingHotplugEvents().empty()); -} - -} // namespace -} // namespace android \ No newline at end of file diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index f95b878ec0..82eb3bfc18 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -321,9 +321,8 @@ public: return mFlinger->handleTransactionLocked(transactionFlags); } - auto onHotplugReceived(int32_t sequenceId, hal::HWDisplayId display, - hal::Connection connection) { - return mFlinger->onHotplugReceived(sequenceId, display, connection); + void onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, hal::Connection connection) { + mFlinger->onComposerHalHotplug(hwcDisplayId, connection); } auto setDisplayStateLocked(const DisplayState& s) { @@ -437,7 +436,6 @@ public: auto& mutablePowerAdvisor() { return mFlinger->mPowerAdvisor; } auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; } - auto& mutableComposerSequenceId() { return mFlinger->getBE().mComposerSequenceId; } auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; } auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; } auto& mutableInternalHwcDisplayId() { return getHwComposer().mInternalHwcDisplayId; } -- cgit v1.2.3-59-g8ed1b From a516c0009ed06d998e093216f07fc33d7e4a7fb9 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Fri, 7 May 2021 14:36:58 -0700 Subject: SF: Clean up HWC2::Layer ownership Changes the HWC2::Display::createLayer() call to return a shared_ptr instead of a bare pointer. Also if the HWC2::Display is disconnected, instead of directly destroying the HWC2::Layers associated with the display, a new call is made to clear the display information from the layer. For safety, checks are added to take an early out if the display information isn't set for any call where it is used. The CompositionEngine code was already creating a shared_ptr for the createLayer call, and expecting the pointer to be valid until it released it via destroyLayer. However a hotplug disconnect could leave the CompositionEngine code holding an invalid pointer until the next display refresh, and it could lead to bad memory accesses if the pointer was dereferenced. CompositionEngine itself did not do so -- it released its ownership of the layer (and the associated display) without accessing them. This seems to have only affected "dumpsys SurfaceFlinger", if it happened to be executed after the disconnect, and before another refresh, and only because it tried to print out the HWC layer id. Bug: 181061001 Test: libsurfaceflinger_unittest Test: libcompositionengine_test Test: dumpsys SurfaceFlinger # after hotplug event Change-Id: I508d6aa8ef7a6af848dd54198408d5f311175070 --- .../CompositionEngine/src/Display.cpp | 11 +- .../CompositionEngine/tests/DisplayTest.cpp | 7 +- .../CompositionEngine/tests/MockHWComposer.h | 3 +- services/surfaceflinger/DisplayHardware/HWC2.cpp | 194 +++++++++++++++------ services/surfaceflinger/DisplayHardware/HWC2.h | 33 ++-- .../surfaceflinger/DisplayHardware/HWComposer.cpp | 19 +- .../surfaceflinger/DisplayHardware/HWComposer.h | 8 +- services/surfaceflinger/tests/unittests/Android.bp | 1 + .../tests/unittests/HWComposerTest.cpp | 13 +- .../unittests/mock/DisplayHardware/MockHWC2.cpp | 31 ++++ .../unittests/mock/DisplayHardware/MockHWC2.h | 122 +++++++++++++ 11 files changed, 340 insertions(+), 102 deletions(-) create mode 100644 services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.cpp create mode 100644 services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 7d84cb56d3..1b8532c3f3 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -163,16 +163,7 @@ std::unique_ptr Display::createOutputLayer( if (const auto halDisplayId = HalDisplayId::tryCast(mId); outputLayer && !mIsDisconnected && halDisplayId) { auto& hwc = getCompositionEngine().getHwComposer(); - // Note: For the moment we ensure it is safe to take a reference to the - // HWComposer implementation by destroying all the OutputLayers (and - // hence the HWC2::Layers they own) before setting a new HWComposer. See - // for example SurfaceFlinger::updateVrFlinger(). - // TODO(b/121291683): Make this safer. - auto hwcLayer = - std::shared_ptr(hwc.createLayer(*halDisplayId), - [&hwc, id = *halDisplayId](HWC2::Layer* layer) { - hwc.destroyLayer(id, layer); - }); + auto hwcLayer = hwc.createLayer(*halDisplayId); ALOGE_IF(!hwcLayer, "Failed to create a HWC layer for a HWC supported display %s", getName().c_str()); outputLayer->setHwcLayer(std::move(hwcLayer)); diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 5c9421b54c..c6e56c6963 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -486,16 +486,15 @@ using DisplayCreateOutputLayerTest = FullDisplayImplTestCommon; TEST_F(DisplayCreateOutputLayerTest, setsHwcLayer) { sp layerFE = new StrictMock(); - StrictMock hwcLayer; + auto hwcLayer = std::make_shared>(); EXPECT_CALL(mHwComposer, createLayer(HalDisplayId(DEFAULT_DISPLAY_ID))) - .WillOnce(Return(&hwcLayer)); + .WillOnce(Return(hwcLayer)); auto outputLayer = mDisplay->createOutputLayer(layerFE); - EXPECT_EQ(&hwcLayer, outputLayer->getHwcLayer()); + EXPECT_EQ(hwcLayer.get(), outputLayer->getHwcLayer()); - EXPECT_CALL(mHwComposer, destroyLayer(HalDisplayId(DEFAULT_DISPLAY_ID), &hwcLayer)); outputLayer.reset(); } diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index ee4f331b23..6f4df5ecf4 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -52,8 +52,7 @@ public: std::optional)); MOCK_METHOD2(allocatePhysicalDisplay, void(hal::HWDisplayId, PhysicalDisplayId)); - MOCK_METHOD1(createLayer, HWC2::Layer*(HalDisplayId)); - MOCK_METHOD2(destroyLayer, void(HalDisplayId, HWC2::Layer*)); + MOCK_METHOD1(createLayer, std::shared_ptr(HalDisplayId)); MOCK_METHOD3(getDeviceCompositionChanges, status_t(HalDisplayId, bool, std::optional*)); diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index d04b5f7316..27146ab79c 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -78,7 +78,19 @@ Display::Display(android::Hwc2::Composer& composer, } Display::~Display() { - mLayers.clear(); + // Note: The calls to onOwningDisplayDestroyed() are allowed (and expected) + // to call Display::onLayerDestroyed(). As that call removes entries from + // mLayers, we do not want to have a for loop directly over it here. Since + // the end goal is an empty mLayers anyway, we just go ahead and swap an + // initially empty local container with mLayers, and then enumerate + // the contents of the local container. + Layers destroyingLayers; + std::swap(mLayers, destroyingLayers); + for (const auto& [_, weakLayer] : destroyingLayers) { + if (std::shared_ptr layer = weakLayer.lock()) { + layer->onOwningDisplayDestroyed(); + } + } Error error = Error::NONE; const char* msg; @@ -110,29 +122,21 @@ Error Display::acceptChanges() return static_cast(intError); } -Error Display::createLayer(HWC2::Layer** outLayer) { - if (!outLayer) { - return Error::BAD_PARAMETER; - } +base::expected, hal::Error> Display::createLayer() { HWLayerId layerId = 0; auto intError = mComposer.createLayer(mId, &layerId); auto error = static_cast(intError); if (error != Error::NONE) { - return error; + return base::unexpected(error); } - auto layer = std::make_unique(mComposer, mCapabilities, mId, layerId); - *outLayer = layer.get(); - mLayers.emplace(layerId, std::move(layer)); - return Error::NONE; + auto layer = std::make_shared(mComposer, mCapabilities, *this, layerId); + mLayers.emplace(layerId, layer); + return layer; } -Error Display::destroyLayer(HWC2::Layer* layer) { - if (!layer) { - return Error::BAD_PARAMETER; - } - mLayers.erase(layer->getId()); - return Error::NONE; +void Display::onLayerDestroyed(hal::HWLayerId layerId) { + mLayers.erase(layerId); } bool Display::isVsyncPeriodSwitchSupported() const { @@ -161,7 +165,7 @@ Error Display::getChangedCompositionTypes(std::unordered_mapgetId(), to_string(type).c_str()); - outTypes->emplace(layer, type); + outTypes->emplace(layer.get(), type); } else { ALOGE("getChangedCompositionTypes: invalid layer %" PRIu64 " found" " on display %" PRIu64, layerIds[element], mId); @@ -254,7 +258,7 @@ Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests, if (layer) { auto layerRequest = static_cast(layerRequests[element]); - outLayerRequests->emplace(layer, layerRequest); + outLayerRequests->emplace(layer.get(), layerRequest); } else { ALOGE("getRequests: invalid layer %" PRIu64 " found on display %" PRIu64, layerIds[element], mId); @@ -340,7 +344,7 @@ Error Display::getReleaseFences(std::unordered_map>* out auto layer = getLayerById(layerIds[element]); if (layer) { sp fence(new Fence(fenceFds[element])); - releaseFences.emplace(layer, fence); + releaseFences.emplace(layer.get(), fence); } else { ALOGE("getReleaseFences: invalid layer %" PRIu64 " found on display %" PRIu64, layerIds[element], mId); @@ -550,12 +554,9 @@ void Display::setConnected(bool connected) { // Other Display methods -HWC2::Layer* Display::getLayerById(HWLayerId id) const { - if (mLayers.count(id) == 0) { - return nullptr; - } - - return mLayers.at(id).get(); +std::shared_ptr Display::getLayerById(HWLayerId id) const { + auto it = mLayers.find(id); + return it != mLayers.end() ? it->second.lock() : nullptr; } } // namespace impl @@ -566,47 +567,78 @@ Layer::~Layer() = default; namespace impl { Layer::Layer(android::Hwc2::Composer& composer, const std::unordered_set& capabilities, - HWDisplayId displayId, HWLayerId layerId) + HWC2::Display& display, HWLayerId layerId) : mComposer(composer), mCapabilities(capabilities), - mDisplayId(displayId), + mDisplay(&display), mId(layerId), mColorMatrix(android::mat4()) { - ALOGV("Created layer %" PRIu64 " on display %" PRIu64, layerId, displayId); + ALOGV("Created layer %" PRIu64 " on display %" PRIu64, layerId, display.getId()); } Layer::~Layer() { - auto intError = mComposer.destroyLayer(mDisplayId, mId); + onOwningDisplayDestroyed(); +} + +void Layer::onOwningDisplayDestroyed() { + // Note: onOwningDisplayDestroyed() may be called to perform cleanup by + // either the Layer dtor or by the Display dtor and must be safe to call + // from either path. In particular, the call to Display::onLayerDestroyed() + // is expected to be safe to do, + + if (CC_UNLIKELY(!mDisplay)) { + return; + } + + mDisplay->onLayerDestroyed(mId); + + // Note: If the HWC display was actually disconnected, these calls are will + // return an error. We always make them as there may be other reasons for + // the HWC2::Display to be destroyed. + auto intError = mComposer.destroyLayer(mDisplay->getId(), mId); auto error = static_cast(intError); ALOGE_IF(error != Error::NONE, "destroyLayer(%" PRIu64 ", %" PRIu64 ")" " failed: %s (%d)", - mDisplayId, mId, to_string(error).c_str(), intError); + mDisplay->getId(), mId, to_string(error).c_str(), intError); + + mDisplay = nullptr; } Error Layer::setCursorPosition(int32_t x, int32_t y) { - auto intError = mComposer.setCursorPosition(mDisplayId, mId, x, y); + if (CC_UNLIKELY(!mDisplay)) { + return Error::BAD_DISPLAY; + } + + auto intError = mComposer.setCursorPosition(mDisplay->getId(), mId, x, y); return static_cast(intError); } Error Layer::setBuffer(uint32_t slot, const sp& buffer, const sp& acquireFence) { + if (CC_UNLIKELY(!mDisplay)) { + return Error::BAD_DISPLAY; + } + if (buffer == nullptr && mBufferSlot == slot) { return Error::NONE; } mBufferSlot = slot; int32_t fenceFd = acquireFence->dup(); - auto intError = mComposer.setLayerBuffer(mDisplayId, mId, slot, buffer, - fenceFd); + auto intError = mComposer.setLayerBuffer(mDisplay->getId(), mId, slot, buffer, fenceFd); return static_cast(intError); } Error Layer::setSurfaceDamage(const Region& damage) { + if (CC_UNLIKELY(!mDisplay)) { + return Error::BAD_DISPLAY; + } + if (damage.isRect() && mDamageRegion.isRect() && (damage.getBounds() == mDamageRegion.getBounds())) { return Error::NONE; @@ -617,8 +649,8 @@ Error Layer::setSurfaceDamage(const Region& damage) // rects for HWC Hwc2::Error intError = Hwc2::Error::NONE; if (damage.isRect() && damage.getBounds() == Rect::INVALID_RECT) { - intError = mComposer.setLayerSurfaceDamage(mDisplayId, - mId, std::vector()); + intError = mComposer.setLayerSurfaceDamage(mDisplay->getId(), mId, + std::vector()); } else { size_t rectCount = 0; auto rectArray = damage.getArray(&rectCount); @@ -629,7 +661,7 @@ Error Layer::setSurfaceDamage(const Region& damage) rectArray[rect].right, rectArray[rect].bottom}); } - intError = mComposer.setLayerSurfaceDamage(mDisplayId, mId, hwcRects); + intError = mComposer.setLayerSurfaceDamage(mDisplay->getId(), mId, hwcRects); } return static_cast(intError); @@ -637,34 +669,54 @@ Error Layer::setSurfaceDamage(const Region& damage) Error Layer::setBlendMode(BlendMode mode) { - auto intError = mComposer.setLayerBlendMode(mDisplayId, mId, mode); + if (CC_UNLIKELY(!mDisplay)) { + return Error::BAD_DISPLAY; + } + + auto intError = mComposer.setLayerBlendMode(mDisplay->getId(), mId, mode); return static_cast(intError); } Error Layer::setColor(Color color) { - auto intError = mComposer.setLayerColor(mDisplayId, mId, color); + if (CC_UNLIKELY(!mDisplay)) { + return Error::BAD_DISPLAY; + } + + auto intError = mComposer.setLayerColor(mDisplay->getId(), mId, color); return static_cast(intError); } Error Layer::setCompositionType(Composition type) { - auto intError = mComposer.setLayerCompositionType(mDisplayId, mId, type); + if (CC_UNLIKELY(!mDisplay)) { + return Error::BAD_DISPLAY; + } + + auto intError = mComposer.setLayerCompositionType(mDisplay->getId(), mId, type); return static_cast(intError); } Error Layer::setDataspace(Dataspace dataspace) { + if (CC_UNLIKELY(!mDisplay)) { + return Error::BAD_DISPLAY; + } + if (dataspace == mDataSpace) { return Error::NONE; } mDataSpace = dataspace; - auto intError = mComposer.setLayerDataspace(mDisplayId, mId, mDataSpace); + auto intError = mComposer.setLayerDataspace(mDisplay->getId(), mId, mDataSpace); return static_cast(intError); } Error Layer::setPerFrameMetadata(const int32_t supportedPerFrameMetadata, const android::HdrMetadata& metadata) { + if (CC_UNLIKELY(!mDisplay)) { + return Error::BAD_DISPLAY; + } + if (metadata == mHdrMetadata) { return Error::NONE; } @@ -705,7 +757,7 @@ Error Layer::setPerFrameMetadata(const int32_t supportedPerFrameMetadata, } Error error = static_cast( - mComposer.setLayerPerFrameMetadata(mDisplayId, mId, perFrameMetadatas)); + mComposer.setLayerPerFrameMetadata(mDisplay->getId(), mId, perFrameMetadatas)); if (validTypes & HdrMetadata::HDR10PLUS) { if (CC_UNLIKELY(mHdrMetadata.hdr10plus.size() == 0)) { @@ -715,8 +767,9 @@ Error Layer::setPerFrameMetadata(const int32_t supportedPerFrameMetadata, std::vector perFrameMetadataBlobs; perFrameMetadataBlobs.push_back( {Hwc2::PerFrameMetadataKey::HDR10_PLUS_SEI, mHdrMetadata.hdr10plus}); - Error setMetadataBlobsError = static_cast( - mComposer.setLayerPerFrameMetadataBlobs(mDisplayId, mId, perFrameMetadataBlobs)); + Error setMetadataBlobsError = + static_cast(mComposer.setLayerPerFrameMetadataBlobs(mDisplay->getId(), mId, + perFrameMetadataBlobs)); if (error == Error::NONE) { return setMetadataBlobsError; } @@ -726,46 +779,70 @@ Error Layer::setPerFrameMetadata(const int32_t supportedPerFrameMetadata, Error Layer::setDisplayFrame(const Rect& frame) { + if (CC_UNLIKELY(!mDisplay)) { + return Error::BAD_DISPLAY; + } + Hwc2::IComposerClient::Rect hwcRect{frame.left, frame.top, frame.right, frame.bottom}; - auto intError = mComposer.setLayerDisplayFrame(mDisplayId, mId, hwcRect); + auto intError = mComposer.setLayerDisplayFrame(mDisplay->getId(), mId, hwcRect); return static_cast(intError); } Error Layer::setPlaneAlpha(float alpha) { - auto intError = mComposer.setLayerPlaneAlpha(mDisplayId, mId, alpha); + if (CC_UNLIKELY(!mDisplay)) { + return Error::BAD_DISPLAY; + } + + auto intError = mComposer.setLayerPlaneAlpha(mDisplay->getId(), mId, alpha); return static_cast(intError); } Error Layer::setSidebandStream(const native_handle_t* stream) { + if (CC_UNLIKELY(!mDisplay)) { + return Error::BAD_DISPLAY; + } + if (mCapabilities.count(Capability::SIDEBAND_STREAM) == 0) { ALOGE("Attempted to call setSidebandStream without checking that the " "device supports sideband streams"); return Error::UNSUPPORTED; } - auto intError = mComposer.setLayerSidebandStream(mDisplayId, mId, stream); + auto intError = mComposer.setLayerSidebandStream(mDisplay->getId(), mId, stream); return static_cast(intError); } Error Layer::setSourceCrop(const FloatRect& crop) { + if (CC_UNLIKELY(!mDisplay)) { + return Error::BAD_DISPLAY; + } + Hwc2::IComposerClient::FRect hwcRect{ crop.left, crop.top, crop.right, crop.bottom}; - auto intError = mComposer.setLayerSourceCrop(mDisplayId, mId, hwcRect); + auto intError = mComposer.setLayerSourceCrop(mDisplay->getId(), mId, hwcRect); return static_cast(intError); } Error Layer::setTransform(Transform transform) { + if (CC_UNLIKELY(!mDisplay)) { + return Error::BAD_DISPLAY; + } + auto intTransform = static_cast(transform); - auto intError = mComposer.setLayerTransform(mDisplayId, mId, intTransform); + auto intError = mComposer.setLayerTransform(mDisplay->getId(), mId, intTransform); return static_cast(intError); } Error Layer::setVisibleRegion(const Region& region) { + if (CC_UNLIKELY(!mDisplay)) { + return Error::BAD_DISPLAY; + } + if (region.isRect() && mVisibleRegion.isRect() && (region.getBounds() == mVisibleRegion.getBounds())) { return Error::NONE; @@ -781,22 +858,30 @@ Error Layer::setVisibleRegion(const Region& region) rectArray[rect].right, rectArray[rect].bottom}); } - auto intError = mComposer.setLayerVisibleRegion(mDisplayId, mId, hwcRects); + auto intError = mComposer.setLayerVisibleRegion(mDisplay->getId(), mId, hwcRects); return static_cast(intError); } Error Layer::setZOrder(uint32_t z) { - auto intError = mComposer.setLayerZOrder(mDisplayId, mId, z); + if (CC_UNLIKELY(!mDisplay)) { + return Error::BAD_DISPLAY; + } + + auto intError = mComposer.setLayerZOrder(mDisplay->getId(), mId, z); return static_cast(intError); } // Composer HAL 2.3 Error Layer::setColorTransform(const android::mat4& matrix) { + if (CC_UNLIKELY(!mDisplay)) { + return Error::BAD_DISPLAY; + } + if (matrix == mColorMatrix) { return Error::NONE; } - auto intError = mComposer.setLayerColorTransform(mDisplayId, mId, matrix.asArray()); + auto intError = mComposer.setLayerColorTransform(mDisplay->getId(), mId, matrix.asArray()); Error error = static_cast(intError); if (error != Error::NONE) { return error; @@ -808,7 +893,12 @@ Error Layer::setColorTransform(const android::mat4& matrix) { // Composer HAL 2.4 Error Layer::setLayerGenericMetadata(const std::string& name, bool mandatory, const std::vector& value) { - auto intError = mComposer.setLayerGenericMetadata(mDisplayId, mId, name, mandatory, value); + if (CC_UNLIKELY(!mDisplay)) { + return Error::BAD_DISPLAY; + } + + auto intError = + mComposer.setLayerGenericMetadata(mDisplay->getId(), mId, name, mandatory, value); return static_cast(intError); } diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index e7bf286d08..fae95e79c3 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include #include @@ -84,10 +85,11 @@ public: virtual void setConnected(bool connected) = 0; // For use by Device only virtual const std::unordered_set& getCapabilities() const = 0; virtual bool isVsyncPeriodSwitchSupported() const = 0; + virtual void onLayerDestroyed(hal::HWLayerId layerId) = 0; [[clang::warn_unused_result]] virtual hal::Error acceptChanges() = 0; - [[clang::warn_unused_result]] virtual hal::Error createLayer(Layer** outLayer) = 0; - [[clang::warn_unused_result]] virtual hal::Error destroyLayer(Layer* layer) = 0; + [[clang::warn_unused_result]] virtual base::expected, hal::Error> + createLayer() = 0; [[clang::warn_unused_result]] virtual hal::Error getChangedCompositionTypes( std::unordered_map* outTypes) = 0; [[clang::warn_unused_result]] virtual hal::Error getColorModes( @@ -152,6 +154,8 @@ public: namespace impl { +class Layer; + class Display : public HWC2::Display { public: Display(android::Hwc2::Composer&, const std::unordered_set&, hal::HWDisplayId, @@ -160,10 +164,9 @@ public: // Required by HWC2 hal::Error acceptChanges() override; - hal::Error createLayer(Layer** outLayer) override; - hal::Error destroyLayer(Layer*) override; + base::expected, hal::Error> createLayer() override; hal::Error getChangedCompositionTypes( - std::unordered_map* outTypes) override; + std::unordered_map* outTypes) override; hal::Error getColorModes(std::vector* outModes) const override; // Returns a bitmask which contains HdrMetadata::Type::*. int32_t getSupportedPerFrameMetadata() const override; @@ -174,7 +177,7 @@ public: hal::Error getName(std::string* outName) const override; hal::Error getRequests( hal::DisplayRequest* outDisplayRequests, - std::unordered_map* outLayerRequests) override; + std::unordered_map* outLayerRequests) override; hal::Error getConnectionType(ui::DisplayConnectionType*) const override; hal::Error supportsDoze(bool* outSupport) const override; hal::Error getHdrCapabilities(android::HdrCapabilities* outCapabilities) const override; @@ -185,8 +188,8 @@ public: uint64_t maxFrames) const override; hal::Error getDisplayedContentSample(uint64_t maxFrames, uint64_t timestamp, android::DisplayedFrameStats* outStats) const override; - hal::Error getReleaseFences( - std::unordered_map>* outFences) const override; + hal::Error getReleaseFences(std::unordered_map>* + outFences) const override; hal::Error present(android::sp* outPresentFence) override; hal::Error setClientTarget(uint32_t slot, const android::sp& target, const android::sp& acquireFence, @@ -218,13 +221,14 @@ public: const std::unordered_set& getCapabilities() const override { return mDisplayCapabilities; }; - virtual bool isVsyncPeriodSwitchSupported() const override; + bool isVsyncPeriodSwitchSupported() const override; + void onLayerDestroyed(hal::HWLayerId layerId) override; private: // This may fail (and return a null pointer) if no layer with this ID exists // on this display - Layer* getLayerById(hal::HWLayerId) const; + std::shared_ptr getLayerById(hal::HWLayerId id) const; friend android::TestableSurfaceFlinger; @@ -240,7 +244,8 @@ private: hal::DisplayType mType; bool mIsConnected = false; - std::unordered_map> mLayers; + using Layers = std::unordered_map>; + Layers mLayers; std::once_flag mDisplayCapabilityQueryFlag; std::unordered_set mDisplayCapabilities; @@ -295,10 +300,12 @@ namespace impl { class Layer : public HWC2::Layer { public: Layer(android::Hwc2::Composer& composer, - const std::unordered_set& capabilities, hal::HWDisplayId displayId, + const std::unordered_set& capabilities, HWC2::Display& display, hal::HWLayerId layerId); ~Layer() override; + void onOwningDisplayDestroyed(); + hal::HWLayerId getId() const override { return mId; } hal::Error setCursorPosition(int32_t x, int32_t y) override; @@ -334,7 +341,7 @@ private: android::Hwc2::Composer& mComposer; const std::unordered_set& mCapabilities; - hal::HWDisplayId mDisplayId; + HWC2::Display* mDisplay; hal::HWLayerId mId; // Cached HWC2 data, to ensure the same commands aren't sent to the HWC diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 97cbd0793e..f108a6771a 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -316,20 +316,15 @@ int32_t HWComposer::getAttribute(hal::HWDisplayId hwcDisplayId, hal::HWConfigId return value; } -HWC2::Layer* HWComposer::createLayer(HalDisplayId displayId) { +std::shared_ptr HWComposer::createLayer(HalDisplayId displayId) { RETURN_IF_INVALID_DISPLAY(displayId, nullptr); - HWC2::Layer* layer; - auto error = mDisplayData[displayId].hwcDisplay->createLayer(&layer); - RETURN_IF_HWC_ERROR(error, displayId, nullptr); - return layer; -} - -void HWComposer::destroyLayer(HalDisplayId displayId, HWC2::Layer* layer) { - RETURN_IF_INVALID_DISPLAY(displayId); - - auto error = mDisplayData[displayId].hwcDisplay->destroyLayer(layer); - RETURN_IF_HWC_ERROR(error, displayId); + auto expected = mDisplayData[displayId].hwcDisplay->createLayer(); + if (!expected.has_value()) { + auto error = std::move(expected).error(); + RETURN_IF_HWC_ERROR(error, displayId, nullptr); + } + return std::move(expected).value(); } bool HWComposer::isConnected(PhysicalDisplayId displayId) const { diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 1f81b8db90..f2a4c8d68b 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -122,9 +122,7 @@ public: virtual void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId) = 0; // Attempts to create a new layer on this display - virtual HWC2::Layer* createLayer(HalDisplayId) = 0; - // Destroy a previously created layer - virtual void destroyLayer(HalDisplayId, HWC2::Layer*) = 0; + virtual std::shared_ptr createLayer(HalDisplayId) = 0; // Gets any required composition change requests from the HWC device. // @@ -270,9 +268,7 @@ public: void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId) override; // Attempts to create a new layer on this display - HWC2::Layer* createLayer(HalDisplayId) override; - // Destroy a previously created layer - void destroyLayer(HalDisplayId, HWC2::Layer*) override; + std::shared_ptr createLayer(HalDisplayId) override; status_t getDeviceCompositionChanges( HalDisplayId, bool frameUsesClientComposition, diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 88fb811b52..b33434e34d 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -94,6 +94,7 @@ cc_test { "VSyncReactorTest.cpp", "VsyncConfigurationTest.cpp", "mock/DisplayHardware/MockComposer.cpp", + "mock/DisplayHardware/MockHWC2.cpp", "mock/DisplayHardware/MockPowerAdvisor.cpp", "mock/MockEventThread.cpp", "mock/MockFrameTimeline.cpp", diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp index 138d5cb7d3..57f065aeb8 100644 --- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp +++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp @@ -37,6 +37,7 @@ #include "DisplayHardware/HWComposer.h" #include "DisplayHardware/Hal.h" #include "mock/DisplayHardware/MockComposer.h" +#include "mock/DisplayHardware/MockHWC2.h" // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion" @@ -118,13 +119,19 @@ struct HWComposerLayerTest : public testing::Test { static constexpr hal::HWLayerId kLayerId = static_cast(1002); HWComposerLayerTest(const std::unordered_set& capabilities) - : mCapabilies(capabilities) {} + : mCapabilies(capabilities) { + EXPECT_CALL(mDisplay, getId()).WillRepeatedly(Return(kDisplayId)); + } - ~HWComposerLayerTest() override { EXPECT_CALL(*mHal, destroyLayer(kDisplayId, kLayerId)); } + ~HWComposerLayerTest() override { + EXPECT_CALL(mDisplay, onLayerDestroyed(kLayerId)); + EXPECT_CALL(*mHal, destroyLayer(kDisplayId, kLayerId)); + } std::unique_ptr mHal{new StrictMock()}; const std::unordered_set mCapabilies; - HWC2::impl::Layer mLayer{*mHal, mCapabilies, kDisplayId, kLayerId}; + StrictMock mDisplay; + HWC2::impl::Layer mLayer{*mHal, mCapabilies, mDisplay, kLayerId}; }; struct HWComposerLayerGenericMetadataTest : public HWComposerLayerTest { diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.cpp new file mode 100644 index 0000000000..2647bf4f9d --- /dev/null +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.cpp @@ -0,0 +1,31 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef LOG_TAG +#define LOG_TAG "MockHWC2" + +#include "mock/DisplayHardware/MockHWC2.h" + +namespace android::HWC2::mock { + +// Explicit default instantiation is recommended. +Display::Display() = default; +Display::~Display() = default; + +Layer::Layer() = default; +Layer::~Layer() = default; + +} // namespace android::HWC2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h new file mode 100644 index 0000000000..c3919d9310 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h @@ -0,0 +1,122 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "DisplayHardware/HWC2.h" + +namespace android::HWC2::mock { + +class Display : public HWC2::Display { +public: + Display(); + ~Display() override; + + MOCK_METHOD(hal::HWDisplayId, getId, (), (const, override)); + MOCK_METHOD(bool, isConnected, (), (const, override)); + MOCK_METHOD(void, setConnected, (bool), (override)); + MOCK_METHOD(const std::unordered_set &, getCapabilities, (), + (const, override)); + MOCK_METHOD(bool, isVsyncPeriodSwitchSupported, (), (const, override)); + MOCK_METHOD(void, onLayerDestroyed, (hal::HWLayerId), (override)); + + MOCK_METHOD(hal::Error, acceptChanges, (), (override)); + MOCK_METHOD((base::expected, hal::Error>), createLayer, (), + (override)); + MOCK_METHOD(hal::Error, getChangedCompositionTypes, + ((std::unordered_map *)), (override)); + MOCK_METHOD(hal::Error, getColorModes, (std::vector *), (const, override)); + MOCK_METHOD(int32_t, getSupportedPerFrameMetadata, (), (const, override)); + MOCK_METHOD(hal::Error, getRenderIntents, (hal::ColorMode, std::vector *), + (const, override)); + MOCK_METHOD(hal::Error, getDataspaceSaturationMatrix, (hal::Dataspace, android::mat4 *), + (override)); + MOCK_METHOD(hal::Error, getName, (std::string *), (const, override)); + MOCK_METHOD(hal::Error, getRequests, + (hal::DisplayRequest *, (std::unordered_map *)), + (override)); + MOCK_METHOD(hal::Error, getConnectionType, (ui::DisplayConnectionType *), (const, override)); + MOCK_METHOD(hal::Error, supportsDoze, (bool *), (const, override)); + MOCK_METHOD(hal::Error, getHdrCapabilities, (android::HdrCapabilities *), (const, override)); + MOCK_METHOD(hal::Error, getDisplayedContentSamplingAttributes, + (hal::PixelFormat *, hal::Dataspace *, uint8_t *), (const, override)); + MOCK_METHOD(hal::Error, setDisplayContentSamplingEnabled, (bool, uint8_t, uint64_t), + (const, override)); + MOCK_METHOD(hal::Error, getDisplayedContentSample, + (uint64_t, uint64_t, android::DisplayedFrameStats *), (const, override)); + MOCK_METHOD(hal::Error, getReleaseFences, + ((std::unordered_map> *)), (const, override)); + MOCK_METHOD(hal::Error, present, (android::sp *), (override)); + MOCK_METHOD(hal::Error, setClientTarget, + (uint32_t, const android::sp &, + const android::sp &, hal::Dataspace), + (override)); + MOCK_METHOD(hal::Error, setColorMode, (hal::ColorMode, hal::RenderIntent), (override)); + MOCK_METHOD(hal::Error, setColorTransform, (const android::mat4 &, hal::ColorTransform), + (override)); + MOCK_METHOD(hal::Error, setOutputBuffer, + (const android::sp &, const android::sp &), + (override)); + MOCK_METHOD(hal::Error, setPowerMode, (hal::PowerMode), (override)); + MOCK_METHOD(hal::Error, setVsyncEnabled, (hal::Vsync), (override)); + MOCK_METHOD(hal::Error, validate, (uint32_t *, uint32_t *), (override)); + MOCK_METHOD(hal::Error, presentOrValidate, + (uint32_t *, uint32_t *, android::sp *, uint32_t *), (override)); + MOCK_METHOD(std::future, setDisplayBrightness, (float), (override)); + MOCK_METHOD(hal::Error, setActiveConfigWithConstraints, + (hal::HWConfigId, const hal::VsyncPeriodChangeConstraints &, + hal::VsyncPeriodChangeTimeline *), + (override)); + MOCK_METHOD(hal::Error, setAutoLowLatencyMode, (bool), (override)); + MOCK_METHOD(hal::Error, getSupportedContentTypes, (std::vector *), + (const, override)); + MOCK_METHOD(hal::Error, setContentType, (hal::ContentType), (override)); + MOCK_METHOD(hal::Error, getClientTargetProperty, (hal::ClientTargetProperty *), (override)); +}; + +class Layer : public HWC2::Layer { +public: + Layer(); + ~Layer() override; + + MOCK_METHOD(hal::HWLayerId, getId, (), (const, override)); + MOCK_METHOD(hal::Error, setCursorPosition, (int32_t, int32_t), (override)); + MOCK_METHOD(hal::Error, setBuffer, + (uint32_t, const android::sp &, + const android::sp &), + (override)); + MOCK_METHOD(hal::Error, setSurfaceDamage, (const android::Region &), (override)); + MOCK_METHOD(hal::Error, setBlendMode, (hal::BlendMode), (override)); + MOCK_METHOD(hal::Error, setColor, (hal::Color), (override)); + MOCK_METHOD(hal::Error, setCompositionType, (hal::Composition), (override)); + MOCK_METHOD(hal::Error, setDataspace, (android::ui::Dataspace), (override)); + MOCK_METHOD(hal::Error, setPerFrameMetadata, (const int32_t, const android::HdrMetadata &), + (override)); + MOCK_METHOD(hal::Error, setDisplayFrame, (const android::Rect &), (override)); + MOCK_METHOD(hal::Error, setPlaneAlpha, (float), (override)); + MOCK_METHOD(hal::Error, setSidebandStream, (const native_handle_t *), (override)); + MOCK_METHOD(hal::Error, setSourceCrop, (const android::FloatRect &), (override)); + MOCK_METHOD(hal::Error, setTransform, (hal::Transform), (override)); + MOCK_METHOD(hal::Error, setVisibleRegion, (const android::Region &), (override)); + MOCK_METHOD(hal::Error, setZOrder, (uint32_t), (override)); + MOCK_METHOD(hal::Error, setColorTransform, (const android::mat4 &), (override)); + MOCK_METHOD(hal::Error, setLayerGenericMetadata, + (const std::string &, bool, const std::vector &), (override)); +}; + +} // namespace android::HWC2::mock -- cgit v1.2.3-59-g8ed1b From 05fc88302dee5dcd6b0960005789c4214d32c30d Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 18 May 2021 23:16:37 +0000 Subject: Clear mForceTraversal Fixes regression from 6bdec7d9c62ed47f9fd0e0cb9e59f0cbe48b4bae Change-Id: I839682e5daa407994de3714803e1e92c0bbbc4fe Test: go/wm-smoke Fixes: 188546439 --- services/surfaceflinger/SurfaceFlinger.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 442b4bb934..a829b12851 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2878,6 +2878,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { // Commit layer transactions. This needs to happen after display transactions are // committed because some geometry logic relies on display orientation. if ((transactionFlags & eTraversalNeeded) || mForceTraversal || displayTransactionNeeded) { + mForceTraversal = false; mCurrentState.traverse([&](Layer* layer) { uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); if (!trFlags && !displayTransactionNeeded) return; -- cgit v1.2.3-59-g8ed1b From 75e0373d69afc4d4cdf3d558ffdbec72fa9c11cb Mon Sep 17 00:00:00 2001 From: Victor Hsieh Date: Mon, 10 May 2021 16:28:54 -0700 Subject: Make available to com.android.compos apex Bug: 186126404 Test: m Change-Id: Ie649a17a3fae4f2bb668d8a084b9945716e2a48e (cherry picked from commit 7d7de5b488f4bb351f04edf9e5daf0605f1a1fb9) --- libs/binder/rust/Android.bp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp index 49d3401a4f..7d655d8c3e 100644 --- a/libs/binder/rust/Android.bp +++ b/libs/binder/rust/Android.bp @@ -26,6 +26,7 @@ rust_library { }, apex_available: [ "//apex_available:platform", + "com.android.compos", "com.android.virt", ], } @@ -48,6 +49,7 @@ rust_library { }, apex_available: [ "//apex_available:platform", + "com.android.compos", "com.android.virt", ], lints: "none", @@ -99,6 +101,7 @@ rust_bindgen { }, apex_available: [ "//apex_available:platform", + "com.android.compos", "com.android.virt", ], } -- cgit v1.2.3-59-g8ed1b From cdd722bb39c0a943b191f74677056343640ecdca Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Wed, 19 May 2021 14:29:05 -0700 Subject: Fix caching runtime toggle 1. When caching is disabled, the override info must be cleared before repainting the screen. Otherwise, ignored layers may persist in HWC. 2. Dispatch the caching toggle on the main thread, to de-risk threading issues. Bug: 188611599 Test: adb shell service call SurfaceFlinger i32 1040 0, then check dumpsys Change-Id: I6926e69fb9762209c958beceb2679cd7a5806306 --- .../CompositionEngine/src/Output.cpp | 8 ++++ .../CompositionEngine/tests/OutputTest.cpp | 21 +++++++++++ services/surfaceflinger/SurfaceFlinger.cpp | 43 +++++++++++++--------- 3 files changed, 55 insertions(+), 17 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index bf36355fd8..088a400877 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -136,6 +136,14 @@ void Output::setLayerCachingEnabled(bool enabled) { } else { mPlanner.reset(); } + + for (auto* outputLayer : getOutputLayersOrderedByZ()) { + if (!outputLayer) { + continue; + } + + outputLayer->editState().overrideInfo = {}; + } } void Output::setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect, diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 11736d1e07..6677f408ad 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -259,6 +259,27 @@ TEST_F(OutputTest, setLayerCachingEnabled_disablesCaching) { EXPECT_FALSE(mOutput->plannerEnabled()); } +TEST_F(OutputTest, setLayerCachingEnabled_disablesCachingAndResetsOverrideInfo) { + renderengine::mock::RenderEngine renderEngine; + const auto kSize = ui::Size(1, 1); + EXPECT_CALL(*mRenderSurface, getSize()).WillRepeatedly(ReturnRef(kSize)); + mOutput->setLayerCachingEnabled(true); + + // Inject some layers + InjectedLayer layer; + layer.outputLayerState.overrideInfo.buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(), renderEngine, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); + injectOutputLayer(layer); + // inject a null layer to check for null exceptions + injectNullOutputLayer(); + + EXPECT_NE(nullptr, layer.outputLayerState.overrideInfo.buffer); + mOutput->setLayerCachingEnabled(false); + EXPECT_EQ(nullptr, layer.outputLayerState.overrideInfo.buffer); +} + /* * Output::setProjection() */ diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1c02d5c157..34ad96c18c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5627,23 +5627,32 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r // Second argument is an optional uint64 - if present, then limits enabling/disabling // caching to a particular physical display case 1040: { - n = data.readInt32(); - std::optional inputId = std::nullopt; - if (uint64_t inputDisplayId; data.readUint64(&inputDisplayId) == NO_ERROR) { - inputId = DisplayId::fromValue(inputDisplayId); - if (!inputId || getPhysicalDisplayToken(*inputId)) { - ALOGE("No display with id: %" PRIu64, inputDisplayId); - return NAME_NOT_FOUND; - } - } - { - Mutex::Autolock lock(mStateLock); - mLayerCachingEnabled = n != 0; - for (const auto& [_, display] : mDisplays) { - if (!inputId || *inputId == display->getPhysicalId()) { - display->enableLayerCaching(mLayerCachingEnabled); - } - } + status_t error = + schedule([&] { + n = data.readInt32(); + std::optional inputId = std::nullopt; + if (uint64_t inputDisplayId; + data.readUint64(&inputDisplayId) == NO_ERROR) { + inputId = DisplayId::fromValue(inputDisplayId); + if (!inputId || getPhysicalDisplayToken(*inputId)) { + ALOGE("No display with id: %" PRIu64, inputDisplayId); + return NAME_NOT_FOUND; + } + } + { + Mutex::Autolock lock(mStateLock); + mLayerCachingEnabled = n != 0; + for (const auto& [_, display] : mDisplays) { + if (!inputId || *inputId == display->getPhysicalId()) { + display->enableLayerCaching(mLayerCachingEnabled); + } + } + } + return OK; + }).get(); + + if (error != OK) { + return error; } invalidateHwcGeometry(); repaintEverything(); -- cgit v1.2.3-59-g8ed1b From d4db32b97c277e1d174005282128547419b69b97 Mon Sep 17 00:00:00 2001 From: Collin Fijalkovich Date: Fri, 21 May 2021 11:41:40 -0700 Subject: ATRACE: Add fastrpc_stat to the memory category Enables the fastrpc_stat tracepoint when the atrace memory category is selected. Bug: 170189835 Test: Validated trace with memory category enabled Change-Id: I002662549153cf3bbf96c0d5794fc9e2a970758e --- cmds/atrace/atrace.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index 79419d3ae6..021fdb53b2 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -245,6 +245,7 @@ static const TracingCategory k_categories[] = { { OPT, "events/kmem/ion_heap_shrink/enable" }, { OPT, "events/ion/ion_stat/enable" }, { OPT, "events/gpu_mem/gpu_mem_total/enable" }, + { OPT, "events/fastrpc/fastrpc_dma_stat/enable" }, } }, { "thermal", "Thermal event", 0, { { REQ, "events/thermal/thermal_temperature/enable" }, -- cgit v1.2.3-59-g8ed1b From 97b0d3b5fcbe4dcf0a8d359f52027bbf49a8f387 Mon Sep 17 00:00:00 2001 From: liushenxiang Date: Fri, 21 May 2021 20:24:09 +0800 Subject: [BugFix] Reset key repeating in case a keyboard device was disabled or enabled. The "resetKeyRepeatLocked" will never be called when we disable a keyboard device. In this case, if we long click a key on keyboard and it began to repeat. Then we disable the keyboard. We find that the key repeating will never stop until a next key event come. Test: atest inputflinger_tests Signed-off-by: liushenxiang Change-Id: Ic0e37d1e1e447d4965f3fbb479e0eca7c726a6ab --- services/inputflinger/dispatcher/InputDispatcher.cpp | 5 +++++ services/inputflinger/tests/InputDispatcher_test.cpp | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 7e069c80d0..1117ecd715 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -1256,6 +1256,11 @@ bool InputDispatcher::dispatchDeviceResetLocked(nsecs_t currentTime, entry.deviceId); #endif + // Reset key repeating in case a keyboard device was disabled or enabled. + if (mKeyRepeatState.lastKeyEntry && mKeyRepeatState.lastKeyEntry->deviceId == entry.deviceId) { + resetKeyRepeatLocked(); + } + CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, "device was reset"); options.deviceId = entry.deviceId; synthesizeCancelationEventsForAllConnectionsLocked(options); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 93aa6aca6d..b091473633 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -2858,6 +2858,16 @@ TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatStopsAfterRepeatingK mWindow->assertNoEvents(); } +TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterDisableInputDevice) { + sendAndConsumeKeyDown(DEVICE_ID); + expectKeyRepeatOnce(1 /*repeatCount*/); + NotifyDeviceResetArgs args(10 /*id*/, 20 /*eventTime*/, DEVICE_ID); + mDispatcher->notifyDeviceReset(&args); + mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT, + AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_LONG_PRESS); + mWindow->assertNoEvents(); +} + TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFromInputDispatcher) { sendAndConsumeKeyDown(1 /* deviceId */); for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) { -- cgit v1.2.3-59-g8ed1b From 225ab764eecec4376fef41c3c62a8d72d6651c28 Mon Sep 17 00:00:00 2001 From: Svet Ganov Date: Thu, 20 May 2021 16:10:02 +0000 Subject: Switch media fw permissions checks to AttributionSource (native) Attribution source is the abstraction to capture the data flows for private data across apps. Checking permissions for an attribution source does this for all apps in the chain that would receive the data as well as the relevant app ops are checked/noted/started as needed. bug: 158792096 Test: atest CtsMediaTestCases atest CtsPermissionTestCases atest CtsPermission2TestCases atest CtsPermission3TestCases atest CtsPermission4TestCases atest CtsPermission5TestCases atest CtsAppOpsTestCases atest CtsAppOps2TestCases Change-Id: I918cc4dfa653f1e50b4fc71734a37d09b8ca24c4 --- libs/permission/Android.bp | 16 +++--- .../android/content/AttributionSourceState.aidl | 6 +- .../android/permission/IPermissionChecker.aidl | 5 +- .../android/permission/PermissionChecker.cpp | 56 ++++++++++-------- .../include/android/permission/PermissionChecker.h | 67 ++++++++++++++++++---- 5 files changed, 106 insertions(+), 44 deletions(-) diff --git a/libs/permission/Android.bp b/libs/permission/Android.bp index 3243a6b5f4..b00021fd0e 100644 --- a/libs/permission/Android.bp +++ b/libs/permission/Android.bp @@ -11,19 +11,19 @@ aidl_interface { name: "framework-permission-aidl", unstable: true, local_include_dir: "aidl", - backend: { - ndk: { - enabled: false - } - }, + host_supported: true, + vendor_available: true, + double_loadable: true, srcs: [ "aidl/android/content/AttributionSourceState.aidl", "aidl/android/permission/IPermissionChecker.aidl", ], } -cc_library_shared { +cc_library { name: "libpermission", + host_supported: true, + double_loadable: true, cflags: [ "-Wall", "-Wextra", @@ -45,5 +45,7 @@ cc_library_shared { static_libs: [ "framework-permission-aidl-cpp", ], - export_static_lib_headers: ["framework-permission-aidl-cpp"], + export_static_lib_headers: [ + "framework-permission-aidl-cpp" + ], } diff --git a/libs/permission/aidl/android/content/AttributionSourceState.aidl b/libs/permission/aidl/android/content/AttributionSourceState.aidl index b6e54bf153..ed1b37dc0b 100644 --- a/libs/permission/aidl/android/content/AttributionSourceState.aidl +++ b/libs/permission/aidl/android/content/AttributionSourceState.aidl @@ -23,8 +23,10 @@ package android.content; * {@hide} */ parcelable AttributionSourceState { + /** The PID that is accessing the permission protected data. */ + int pid = -1; /** The UID that is accessing the permission protected data. */ - int uid; + int uid = -1; /** The package that is accessing the permission protected data. */ @nullable @utf8InCpp String packageName; /** The attribution tag of the app accessing the permission protected data. */ @@ -36,5 +38,5 @@ parcelable AttributionSourceState { /** The next app to receive the permission protected data. */ // TODO: We use an array as a workaround - the C++ backend doesn't // support referring to the parcelable as it expects ctor/dtor - @nullable AttributionSourceState[] next; + AttributionSourceState[] next; } diff --git a/libs/permission/aidl/android/permission/IPermissionChecker.aidl b/libs/permission/aidl/android/permission/IPermissionChecker.aidl index 1f0e32d248..d3a331e1e2 100644 --- a/libs/permission/aidl/android/permission/IPermissionChecker.aidl +++ b/libs/permission/aidl/android/permission/IPermissionChecker.aidl @@ -28,9 +28,10 @@ interface IPermissionChecker { int checkPermission(String permission, in AttributionSourceState attributionSource, @nullable String message, boolean forDataDelivery, boolean startDataDelivery, - boolean fromDatasource); + boolean fromDatasource, int attributedOp); - void finishDataDelivery(String op, in AttributionSourceState attributionSource); + void finishDataDelivery(int op, in AttributionSourceState attributionSource, + boolean fromDatasource); int checkOp(int op, in AttributionSourceState attributionSource, String message, boolean forDataDelivery, boolean startDataDelivery); diff --git a/libs/permission/android/permission/PermissionChecker.cpp b/libs/permission/android/permission/PermissionChecker.cpp index a8083ee410..008afad607 100644 --- a/libs/permission/android/permission/PermissionChecker.cpp +++ b/libs/permission/android/permission/PermissionChecker.cpp @@ -29,7 +29,7 @@ #endif #define LOG_TAG "PermissionChecker" -namespace android { +namespace android::permission { using android::content::AttributionSourceState; @@ -37,7 +37,7 @@ PermissionChecker::PermissionChecker() { } -sp PermissionChecker::getService() +sp PermissionChecker::getService() { static String16 permission_checker("permission_checker"); @@ -59,56 +59,66 @@ sp PermissionChecker::getService() sleep(1); } else { mService = interface_cast(binder); + break; } } return mService; } -PermissionChecker::PermissionResult - PermissionChecker::checkPermissionForDataDeliveryFromDatasource( - const String16& permission, AttributionSourceState& attributionSource, - const String16& message) +PermissionChecker::PermissionResult PermissionChecker::checkPermissionForDataDeliveryFromDatasource( + const String16& permission, const AttributionSourceState& attributionSource, + const String16& message, int32_t attributedOpCode) { - return static_cast(checkPermission(permission, attributionSource, message, - /*forDataDelivery*/ true, /*startDataDelivery*/ false,/*fromDatasource*/ true)); + return checkPermission(permission, attributionSource, message, /*forDataDelivery*/ true, + /*startDataDelivery*/ false,/*fromDatasource*/ true, attributedOpCode); } PermissionChecker::PermissionResult - PermissionChecker::checkPermissionForStartDataDeliveryFromDatasource( - const String16& permission, AttributionSourceState& attributionSource, - const String16& message) + PermissionChecker::checkPermissionForStartDataDeliveryFromDatasource( + const String16& permission, const AttributionSourceState& attributionSource, + const String16& message, int32_t attributedOpCode) +{ + return checkPermission(permission, attributionSource, message, /*forDataDelivery*/ true, + /*startDataDelivery*/ true, /*fromDatasource*/ true, attributedOpCode); +} + +PermissionChecker::PermissionResult PermissionChecker::checkPermissionForPreflightFromDatasource( + const String16& permission, const AttributionSourceState& attributionSource, + const String16& message, int32_t attributedOpCode) { - return static_cast(checkPermission(permission, attributionSource, message, - /*forDataDelivery*/ true, /*startDataDelivery*/ true, /*fromDatasource*/ true)); + return checkPermission(permission, attributionSource, message, /*forDataDelivery*/ false, + /*startDataDelivery*/ false, /*fromDatasource*/ true, attributedOpCode); } -void PermissionChecker::finishDataDelivery(const String16& op, - AttributionSourceState& attributionSource) +void PermissionChecker::finishDataDeliveryFromDatasource(int32_t op, + const AttributionSourceState& attributionSource) { sp service = getService(); if (service != nullptr) { - binder::Status status = service->finishDataDelivery(op, attributionSource); + binder::Status status = service->finishDataDelivery(op, attributionSource, + /*fromDatasource*/ true); if (!status.isOk()) { ALOGE("finishDataDelivery failed: %s", status.exceptionMessage().c_str()); } } } -int32_t PermissionChecker::checkPermission(const String16& permission, - AttributionSourceState& attributionSource, const String16& message, - bool forDataDelivery, bool startDataDelivery, bool fromDatasource) +PermissionChecker::PermissionResult PermissionChecker::checkPermission(const String16& permission, + const AttributionSourceState& attributionSource, const String16& message, + bool forDataDelivery, bool startDataDelivery, bool fromDatasource, + int32_t attributedOpCode) { sp service = getService(); if (service != nullptr) { int32_t result; binder::Status status = service->checkPermission(permission, attributionSource, message, - forDataDelivery, startDataDelivery, fromDatasource, &result); + forDataDelivery, startDataDelivery, fromDatasource, attributedOpCode, &result); if (status.isOk()) { - return result; + return static_cast(result); } ALOGE("checkPermission failed: %s", status.exceptionMessage().c_str()); } - return PERMISSION_DENIED; + return PERMISSION_HARD_DENIED; } -} // namespace android +} // namespace android::permission diff --git a/libs/permission/include/android/permission/PermissionChecker.h b/libs/permission/include/android/permission/PermissionChecker.h index 20ab51fc8a..308d7942a4 100644 --- a/libs/permission/include/android/permission/PermissionChecker.h +++ b/libs/permission/include/android/permission/PermissionChecker.h @@ -30,6 +30,8 @@ // --------------------------------------------------------------------------- namespace android { +namespace permission { + using android::content::AttributionSourceState; using android::permission::IPermissionChecker; @@ -71,7 +73,8 @@ public: * Checks whether a given data access chain described by the given attribution source * has a given permission and whether the app op that corresponds to this permission * is allowed. Call this method if you are the datasource which would not blame you for - * access to the data since you are the data. Note that the attribution source chain + * access to the data since you are the data. Use this API if you are the datasource of + * the protected state. * * NOTE: The attribution source should be for yourself with its next attribution * source being the app that would receive the data from you. @@ -82,18 +85,49 @@ public: * @param permission The permission to check. * @param attributionSource The attribution chain to check. * @param message A message describing the reason the permission was checked. + * @param attributedOpCode The op code towards which to blame the access. If this + * is a valid app op the op corresponding to the checked permission (if such) + * would only be checked to ensure it is allowed and if that succeeds the + * noting would be against the attributed op. * @return The permission check result which is either PERMISSION_GRANTED, * or PERMISSION_SOFT_DENIED or PERMISSION_HARD_DENIED. */ PermissionChecker::PermissionResult checkPermissionForDataDeliveryFromDatasource( - const String16& permission, AttributionSourceState& attributionSource, - const String16& message); + const String16& permission, const AttributionSourceState& attributionSource, + const String16& message, int32_t attributedOpCode); + + /** + * Checks whether a given data access chain described by the given attribution source + * has a given permission and whether the app op that corresponds to this permission + * is allowed. The app ops are not noted/started. + * + * NOTE: The attribution source should be for yourself with its next attribution + * source being the app that would receive the data from you. + * + * NOTE: Use this method only for permission checks at the preflight point where you + * will not deliver the permission protected data to clients but schedule permission + * data delivery, apps register listeners, etc. + * + * @param permission The permission to check. + * @param attributionSource The attribution chain to check. + * @param message A message describing the reason the permission was checked. + * @param attributedOpCode The op code towards which to blame the access. If this + * is a valid app op the op corresponding to the checked permission (if such) + * would only be checked to ensure it is allowed and if that succeeds the + * starting would be against the attributed op. + * @return The permission check result which is either PERMISSION_GRANTED, + * or PERMISSION_SOFT_DENIED or PERMISSION_HARD_DENIED. + */ + PermissionResult checkPermissionForPreflightFromDatasource( + const String16& permission, const AttributionSourceState& attributionSource, + const String16& message, int32_t attributedOpCode); /** * Checks whether a given data access chain described by the given attribution source * has a given permission and whether the app op that corresponds to this permission * is allowed. The app ops are also marked as started. This is useful for long running - * permissions like camera and microphone. + * permissions like camera and microphone. Use this API if you are the datasource of + * the protected state. * * NOTE: The attribution source should be for yourself with its next attribution * source being the app that would receive the data from you. @@ -104,32 +138,45 @@ public: * @param permission The permission to check. * @param attributionSource The attribution chain to check. * @param message A message describing the reason the permission was checked. + * @param attributedOpCode The op code towards which to blame the access. If this + * is a valid app op the op corresponding to the checked permission (if such) + * would only be checked to ensure it is allowed and if that succeeds the + * starting would be against the attributed op. * @return The permission check result which is either PERMISSION_GRANTED, * or PERMISSION_SOFT_DENIED or PERMISSION_HARD_DENIED. */ PermissionResult checkPermissionForStartDataDeliveryFromDatasource( - const String16& permission, AttributionSourceState& attributionSource, - const String16& message); + const String16& permission, const AttributionSourceState& attributionSource, + const String16& message, int32_t attributedOpCode); /** * Finishes an ongoing op for data access chain described by the given - * attribution source. + * attribution source. Use this API if you are the datasource of the protected + * state. Use this API if you are the datasource of the protected state. + * + * NOTE: The attribution source should be for yourself with its next attribution + * source being the app that would receive the data from you. * * @param op The op to finish. * @param attributionSource The attribution chain for which to finish data delivery. + * @param attributedOpCode The op code towards which to blame the access. If this + * is a valid app op it is the op that would be finished. */ - void finishDataDelivery(const String16& op, AttributionSourceState& attributionSource); + void finishDataDeliveryFromDatasource(int32_t op, + const AttributionSourceState& attributionSource); private: Mutex mLock; sp mService; sp getService(); - int32_t checkPermission(const String16& permission, AttributionSourceState& attributionSource, + PermissionResult checkPermission(const String16& permission, + const AttributionSourceState& attributionSource, const String16& message, bool forDataDelivery, bool startDataDelivery, - bool fromDatasource); + bool fromDatasource, int32_t attributedOpCode); }; +} // namespace permission } // namespace android -- cgit v1.2.3-59-g8ed1b From bc1e7b178af37a8a39fdf2b1b7c97dd30652d1be Mon Sep 17 00:00:00 2001 From: Svet Ganov Date: Wed, 2 Jun 2021 17:16:23 +0000 Subject: Exclude libpermission on Darwin bug:189918791 Test: builds Change-Id: Ice2ac3b95d9ddf3cdfe5083eb819ae40b91b18c5 --- libs/permission/Android.bp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libs/permission/Android.bp b/libs/permission/Android.bp index b00021fd0e..0eeca5469e 100644 --- a/libs/permission/Android.bp +++ b/libs/permission/Android.bp @@ -24,6 +24,11 @@ cc_library { name: "libpermission", host_supported: true, double_loadable: true, + target: { + darwin: { + enabled: false, + }, + }, cflags: [ "-Wall", "-Wextra", -- cgit v1.2.3-59-g8ed1b From 343ab843bd668ff687c7dcba2006775a2b03549f Mon Sep 17 00:00:00 2001 From: Steve Pfetsch Date: Wed, 2 Jun 2021 18:37:28 +0000 Subject: TouchVideoDevice: Silence log spam When it was originally written, the TouchVideoDevice could expect that every queued heatmap frame would correspond directly to a set of touch coordinates. This is no longer true because touch coordinates may be dropped before reaching InputFlinger. Therefore, heatmap frames may be dropped frequently and the accompanying error message is less valuable. Bug: 184000818 Bug: 189901803 Change-Id: I9ba848c70c0c5014e6ed5c2af8fd0f5629971254 --- services/inputflinger/reader/TouchVideoDevice.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/services/inputflinger/reader/TouchVideoDevice.cpp b/services/inputflinger/reader/TouchVideoDevice.cpp index c075078528..c7c8e28419 100644 --- a/services/inputflinger/reader/TouchVideoDevice.cpp +++ b/services/inputflinger/reader/TouchVideoDevice.cpp @@ -169,8 +169,9 @@ size_t TouchVideoDevice::readAndQueueFrames() { mFrames.insert(mFrames.end(), std::make_move_iterator(frames.begin()), std::make_move_iterator(frames.end())); if (mFrames.size() > MAX_QUEUE_SIZE) { - ALOGE("More than %zu frames have been accumulated. Dropping %zu frames", MAX_QUEUE_SIZE, - mFrames.size() - MAX_QUEUE_SIZE); + // A user-space grip suppression process may be processing the video frames, and holding + // back the input events. This could result in video frames being produced without the + // matching input events. Drop the oldest frame here to prepare for the next input event. mFrames.erase(mFrames.begin(), mFrames.end() - MAX_QUEUE_SIZE); } return numFrames; -- cgit v1.2.3-59-g8ed1b From dda9bbadaf7aedf4cc5938ab131147a7bd05ce63 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Wed, 3 Feb 2021 18:56:00 -0800 Subject: FTL: Add SmallMap mutators Add try_emplace, try_replace, emplace_or_replace, and erase. Rename getters so that `find` returns an iterator like standard containers. Bug: 185536303 Test: ftl_test Change-Id: I095bb800c6bd786b9fceaf632aa06b2d6cdadb71 --- include/ftl/small_map.h | 132 +++++++++++++++++++----- include/ftl/small_vector.h | 2 +- libs/ftl/small_map_test.cpp | 243 +++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 340 insertions(+), 37 deletions(-) diff --git a/include/ftl/small_map.h b/include/ftl/small_map.h index 84c15ebdca..bcaba82934 100644 --- a/include/ftl/small_map.h +++ b/include/ftl/small_map.h @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -28,7 +29,10 @@ namespace android::ftl { // Associative container with unique, unordered keys. Unlike std::unordered_map, key-value pairs are // stored in contiguous storage for cache efficiency. The map is allocated statically until its size -// exceeds N, at which point mappings are relocated to dynamic memory. +// exceeds N, at which point mappings are relocated to dynamic memory. The try_emplace operation has +// a non-standard analogue try_replace that destructively emplaces. The API also defines an in-place +// counterpart to insert_or_assign: emplace_or_replace. Lookup is done not via a subscript operator, +// but immutable getters that can optionally transform the value. // // SmallMap unconditionally allocates on the heap. // @@ -43,16 +47,19 @@ namespace android::ftl { // assert(!map.dynamic()); // // assert(map.contains(123)); -// assert(map.find(42, [](const std::string& s) { return s.size(); }) == 3u); +// assert(map.get(42, [](const std::string& s) { return s.size(); }) == 3u); // -// const auto opt = map.find(-1); +// const auto opt = map.get(-1); // assert(opt); // // std::string& ref = *opt; // assert(ref.empty()); // ref = "xyz"; // -// assert(map == SmallMap(ftl::init::map(-1, "xyz")(42, "???")(123, "abc"))); +// map.emplace_or_replace(0, "vanilla", 2u, 3u); +// assert(map.dynamic()); +// +// assert(map == SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc"))); // template class SmallMap final { @@ -80,12 +87,7 @@ class SmallMap final { // The syntax for listing pairs is as follows: // // ftl::SmallMap map = ftl::init::map(123, "abc")(-1)(42, 3u, '?'); - // // static_assert(std::is_same_v>); - // assert(map.size() == 3u); - // assert(map.contains(-1) && map.find(-1)->get().empty()); - // assert(map.contains(42) && map.find(42)->get() == "???"); - // assert(map.contains(123) && map.find(123)->get() == "abc"); // // The types of the key and value are deduced if the first pair contains exactly two arguments: // @@ -95,7 +97,7 @@ class SmallMap final { template SmallMap(InitializerList, Types...>&& list) : map_(std::move(list)) { - // TODO: Enforce unique keys. + deduplicate(); } size_type max_size() const { return map_.max_size(); } @@ -115,27 +117,27 @@ class SmallMap final { // Returns whether a mapping exists for the given key. bool contains(const key_type& key) const { - return find(key, [](const mapped_type&) {}); + return get(key, [](const mapped_type&) {}); } // Returns a reference to the value for the given key, or std::nullopt if the key was not found. // // ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C'); // - // const auto opt = map.find('c'); + // const auto opt = map.get('c'); // assert(opt == 'C'); // // char d = 'd'; - // const auto ref = map.find('d').value_or(std::ref(d)); + // const auto ref = map.get('d').value_or(std::ref(d)); // ref.get() = 'D'; // assert(d == 'D'); // - auto find(const key_type& key) const -> std::optional> { - return find(key, [](const mapped_type& v) { return std::cref(v); }); + auto get(const key_type& key) const -> std::optional> { + return get(key, [](const mapped_type& v) { return std::cref(v); }); } - auto find(const key_type& key) -> std::optional> { - return find(key, [](mapped_type& v) { return std::ref(v); }); + auto get(const key_type& key) -> std::optional> { + return get(key, [](mapped_type& v) { return std::ref(v); }); } // Returns the result R of a unary operation F on (a constant or mutable reference to) the value @@ -144,11 +146,11 @@ class SmallMap final { // // ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); // - // assert(map.find('c', [](char c) { return std::toupper(c); }) == 'Z'); - // assert(map.find('c', [](char& c) { c = std::toupper(c); })); + // assert(map.get('c', [](char c) { return std::toupper(c); }) == 'Z'); + // assert(map.get('c', [](char& c) { c = std::toupper(c); })); // template > - auto find(const key_type& key, F f) const + auto get(const key_type& key, F f) const -> std::conditional_t, bool, std::optional> { for (auto& [k, v] : *this) { if (k == key) { @@ -165,12 +167,96 @@ class SmallMap final { } template - auto find(const key_type& key, F f) { - return std::as_const(*this).find( + auto get(const key_type& key, F f) { + return std::as_const(*this).get( key, [&f](const mapped_type& v) { return f(const_cast(v)); }); } + // Returns an iterator to an existing mapping for the given key, or the end() iterator otherwise. + const_iterator find(const key_type& key) const { return const_cast(*this).find(key); } + iterator find(const key_type& key) { return find(key, begin()); } + + // Inserts a mapping unless it exists. Returns an iterator to the inserted or existing mapping, + // and whether the mapping was inserted. + // + // On emplace, if the map reaches its static or dynamic capacity, then all iterators are + // invalidated. Otherwise, only the end() iterator is invalidated. + // + template + std::pair try_emplace(const key_type& key, Args&&... args) { + if (const auto it = find(key); it != end()) { + return {it, false}; + } + + auto& ref = map_.emplace_back(std::piecewise_construct, std::forward_as_tuple(key), + std::forward_as_tuple(std::forward(args)...)); + return {&ref, true}; + } + + // Replaces a mapping if it exists, and returns an iterator to it. Returns the end() iterator + // otherwise. + // + // The value is replaced via move constructor, so type V does not need to define copy/move + // assignment, e.g. its data members may be const. + // + // The arguments may directly or indirectly refer to the mapping being replaced. + // + // Iterators to the replaced mapping point to its replacement, and others remain valid. + // + template + iterator try_replace(const key_type& key, Args&&... args) { + const auto it = find(key); + if (it == end()) return it; + map_.replace(it, std::piecewise_construct, std::forward_as_tuple(key), + std::forward_as_tuple(std::forward(args)...)); + return it; + } + + // In-place counterpart of std::unordered_map's insert_or_assign. Returns true on emplace, or + // false on replace. + // + // The value is emplaced and replaced via move constructor, so type V does not need to define + // copy/move assignment, e.g. its data members may be const. + // + // On emplace, if the map reaches its static or dynamic capacity, then all iterators are + // invalidated. Otherwise, only the end() iterator is invalidated. On replace, iterators + // to the replaced mapping point to its replacement, and others remain valid. + // + template + std::pair emplace_or_replace(const key_type& key, Args&&... args) { + const auto [it, ok] = try_emplace(key, std::forward(args)...); + if (ok) return {it, ok}; + map_.replace(it, std::piecewise_construct, std::forward_as_tuple(key), + std::forward_as_tuple(std::forward(args)...)); + return {it, ok}; + } + + // Removes a mapping if it exists, and returns whether it did. + // + // The last() and end() iterators, as well as those to the erased mapping, are invalidated. + // + bool erase(const key_type& key) { return erase(key, begin()); } + private: + iterator find(const key_type& key, iterator first) { + return std::find_if(first, end(), [&key](const auto& pair) { return pair.first == key; }); + } + + bool erase(const key_type& key, iterator first) { + const auto it = find(key, first); + if (it == end()) return false; + map_.unstable_erase(it); + return true; + } + + void deduplicate() { + for (auto it = begin(); it != end();) { + if (const auto key = it->first; ++it != end()) { + while (erase(key, it)); + } + } + } + Map map_; }; @@ -186,7 +272,7 @@ bool operator==(const SmallMap& lhs, const SmallMap& rhs) { for (const auto& [k, v] : lhs) { const auto& lv = v; - if (!rhs.find(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) { + if (!rhs.get(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) { return false; } } diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h index cb0ae359eb..0341435813 100644 --- a/include/ftl/small_vector.h +++ b/include/ftl/small_vector.h @@ -348,7 +348,7 @@ class SmallVector final : ArrayTraits, using Impl::pop_back; void unstable_erase(iterator it) { - if (it != last()) std::iter_swap(it, last()); + if (it != last()) replace(it, std::move(back())); pop_back(); } diff --git a/libs/ftl/small_map_test.cpp b/libs/ftl/small_map_test.cpp index 323b9f91e7..2e81022f38 100644 --- a/libs/ftl/small_map_test.cpp +++ b/libs/ftl/small_map_test.cpp @@ -18,6 +18,9 @@ #include #include +#include + +using namespace std::string_literals; namespace android::test { @@ -35,16 +38,19 @@ TEST(SmallMap, Example) { EXPECT_TRUE(map.contains(123)); - EXPECT_EQ(map.find(42, [](const std::string& s) { return s.size(); }), 3u); + EXPECT_EQ(map.get(42, [](const std::string& s) { return s.size(); }), 3u); - const auto opt = map.find(-1); + const auto opt = map.get(-1); ASSERT_TRUE(opt); std::string& ref = *opt; EXPECT_TRUE(ref.empty()); ref = "xyz"; - EXPECT_EQ(map, SmallMap(ftl::init::map(-1, "xyz")(42, "???")(123, "abc"))); + map.emplace_or_replace(0, "vanilla", 2u, 3u); + EXPECT_TRUE(map.dynamic()); + + EXPECT_EQ(map, SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc"))); } TEST(SmallMap, Construct) { @@ -90,42 +96,253 @@ TEST(SmallMap, Construct) { } } +TEST(SmallMap, UniqueKeys) { + { + // Duplicate mappings are discarded. + const SmallMap map = ftl::init::map(1)(2)(3)(2)(3)(1)(3)(2)(1); + + EXPECT_EQ(map.size(), 3u); + EXPECT_EQ(map.max_size(), 9u); + + using Map = decltype(map); + EXPECT_EQ(map, Map(ftl::init::map(1, 0.f)(2, 0.f)(3, 0.f))); + } + { + // Duplicate mappings may be reordered. + const SmallMap map = ftl::init::map('a', 'A')( + 'b', 'B')('b')('b')('c', 'C')('a')('d')('c')('e', 'E')('d', 'D')('a')('f', 'F'); + + EXPECT_EQ(map.size(), 6u); + EXPECT_EQ(map.max_size(), 12u); + + using Map = decltype(map); + EXPECT_EQ(map, Map(ftl::init::map('a', 'A')('b', 'B')('c', 'C')('d', 'D')('e', 'E')('f', 'F'))); + } +} + TEST(SmallMap, Find) { { // Constant reference. - const ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C'); + const SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C'); - const auto opt = map.find('b'); + const auto opt = map.get('b'); EXPECT_EQ(opt, 'B'); const char d = 'D'; - const auto ref = map.find('d').value_or(std::cref(d)); + const auto ref = map.get('d').value_or(std::cref(d)); EXPECT_EQ(ref.get(), 'D'); } { // Mutable reference. - ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C'); + SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C'); - const auto opt = map.find('c'); + const auto opt = map.get('c'); EXPECT_EQ(opt, 'C'); char d = 'd'; - const auto ref = map.find('d').value_or(std::ref(d)); + const auto ref = map.get('d').value_or(std::ref(d)); ref.get() = 'D'; EXPECT_EQ(d, 'D'); } { // Constant unary operation. - const ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); - EXPECT_EQ(map.find('c', [](char c) { return std::toupper(c); }), 'Z'); + const SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); + EXPECT_EQ(map.get('c', [](char c) { return std::toupper(c); }), 'Z'); } { // Mutable unary operation. - ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); - EXPECT_TRUE(map.find('c', [](char& c) { c = std::toupper(c); })); + SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); + EXPECT_TRUE(map.get('c', [](char& c) { c = std::toupper(c); })); EXPECT_EQ(map, SmallMap(ftl::init::map('c', 'Z')('b', 'y')('a', 'x'))); } } +TEST(SmallMap, TryEmplace) { + SmallMap map; + using Pair = decltype(map)::value_type; + + { + const auto [it, ok] = map.try_emplace(123, "abc"); + ASSERT_TRUE(ok); + EXPECT_EQ(*it, Pair(123, "abc"s)); + } + { + const auto [it, ok] = map.try_emplace(42, 3u, '?'); + ASSERT_TRUE(ok); + EXPECT_EQ(*it, Pair(42, "???"s)); + } + { + const auto [it, ok] = map.try_emplace(-1); + ASSERT_TRUE(ok); + EXPECT_EQ(*it, Pair(-1, std::string())); + EXPECT_FALSE(map.dynamic()); + } + { + // Insertion fails if mapping exists. + const auto [it, ok] = map.try_emplace(42, "!!!"); + EXPECT_FALSE(ok); + EXPECT_EQ(*it, Pair(42, "???")); + EXPECT_FALSE(map.dynamic()); + } + { + // Insertion at capacity promotes the map. + const auto [it, ok] = map.try_emplace(999, "xyz"); + ASSERT_TRUE(ok); + EXPECT_EQ(*it, Pair(999, "xyz")); + EXPECT_TRUE(map.dynamic()); + } + + EXPECT_EQ(map, SmallMap(ftl::init::map(-1, ""s)(42, "???"s)(123, "abc"s)(999, "xyz"s))); +} + +namespace { + +// The mapped type does not require a copy/move assignment operator. +struct String { + template + String(Args... args) : str(args...) {} + const std::string str; + + bool operator==(const String& other) const { return other.str == str; } +}; + +} // namespace + +TEST(SmallMap, TryReplace) { + SmallMap map = ftl::init::map(1, "a")(2, "B"); + using Pair = decltype(map)::value_type; + + { + // Replacing fails unless mapping exists. + const auto it = map.try_replace(3, "c"); + EXPECT_EQ(it, map.end()); + } + { + // Replacement arguments can refer to the replaced mapping. + const auto ref = map.get(2, [](const auto& s) { return s.str[0]; }); + ASSERT_TRUE(ref); + + // Construct std::string from one character. + const auto it = map.try_replace(2, 1u, static_cast(std::tolower(*ref))); + ASSERT_NE(it, map.end()); + EXPECT_EQ(*it, Pair(2, "b")); + } + + EXPECT_FALSE(map.dynamic()); + EXPECT_TRUE(map.try_emplace(3, "abc").second); + EXPECT_TRUE(map.try_emplace(4, "d").second); + EXPECT_TRUE(map.dynamic()); + + { + // Replacing fails unless mapping exists. + const auto it = map.try_replace(5, "e"); + EXPECT_EQ(it, map.end()); + } + { + // Replacement arguments can refer to the replaced mapping. + const auto ref = map.get(3); + ASSERT_TRUE(ref); + + // Construct std::string from substring. + const auto it = map.try_replace(3, ref->get().str, 2u, 1u); + ASSERT_NE(it, map.end()); + EXPECT_EQ(*it, Pair(3, "c")); + } + + EXPECT_EQ(map, SmallMap(ftl::init::map(4, "d"s)(3, "c"s)(2, "b"s)(1, "a"s))); +} + +TEST(SmallMap, EmplaceOrReplace) { + SmallMap map = ftl::init::map(1, "a")(2, "B"); + using Pair = decltype(map)::value_type; + + { + // New mapping is emplaced. + const auto [it, emplace] = map.emplace_or_replace(3, "c"); + EXPECT_TRUE(emplace); + EXPECT_EQ(*it, Pair(3, "c")); + } + { + // Replacement arguments can refer to the replaced mapping. + const auto ref = map.get(2, [](const auto& s) { return s.str[0]; }); + ASSERT_TRUE(ref); + + // Construct std::string from one character. + const auto [it, emplace] = map.emplace_or_replace(2, 1u, static_cast(std::tolower(*ref))); + EXPECT_FALSE(emplace); + EXPECT_EQ(*it, Pair(2, "b")); + } + + EXPECT_FALSE(map.dynamic()); + EXPECT_FALSE(map.emplace_or_replace(3, "abc").second); // Replace. + EXPECT_TRUE(map.emplace_or_replace(4, "d").second); // Emplace. + EXPECT_TRUE(map.dynamic()); + + { + // New mapping is emplaced. + const auto [it, emplace] = map.emplace_or_replace(5, "e"); + EXPECT_TRUE(emplace); + EXPECT_EQ(*it, Pair(5, "e")); + } + { + // Replacement arguments can refer to the replaced mapping. + const auto ref = map.get(3); + ASSERT_TRUE(ref); + + // Construct std::string from substring. + const auto [it, emplace] = map.emplace_or_replace(3, ref->get().str, 2u, 1u); + EXPECT_FALSE(emplace); + EXPECT_EQ(*it, Pair(3, "c")); + } + + EXPECT_EQ(map, SmallMap(ftl::init::map(5, "e"s)(4, "d"s)(3, "c"s)(2, "b"s)(1, "a"s))); +} + +TEST(SmallMap, Erase) { + { + SmallMap map = ftl::init::map(1, '1')(2, '2')(3, '3')(4, '4'); + EXPECT_FALSE(map.dynamic()); + + EXPECT_FALSE(map.erase(0)); // Key not found. + + EXPECT_TRUE(map.erase(2)); + EXPECT_EQ(map, SmallMap(ftl::init::map(1, '1')(3, '3')(4, '4'))); + + EXPECT_TRUE(map.erase(1)); + EXPECT_EQ(map, SmallMap(ftl::init::map(3, '3')(4, '4'))); + + EXPECT_TRUE(map.erase(4)); + EXPECT_EQ(map, SmallMap(ftl::init::map(3, '3'))); + + EXPECT_TRUE(map.erase(3)); + EXPECT_FALSE(map.erase(3)); // Key not found. + + EXPECT_TRUE(map.empty()); + EXPECT_FALSE(map.dynamic()); + } + { + SmallMap map = ftl::init::map(1, '1')(2, '2')(3, '3'); + map.try_emplace(4, '4'); + EXPECT_TRUE(map.dynamic()); + + EXPECT_FALSE(map.erase(0)); // Key not found. + + EXPECT_TRUE(map.erase(2)); + EXPECT_EQ(map, SmallMap(ftl::init::map(1, '1')(3, '3')(4, '4'))); + + EXPECT_TRUE(map.erase(1)); + EXPECT_EQ(map, SmallMap(ftl::init::map(3, '3')(4, '4'))); + + EXPECT_TRUE(map.erase(4)); + EXPECT_EQ(map, SmallMap(ftl::init::map(3, '3'))); + + EXPECT_TRUE(map.erase(3)); + EXPECT_FALSE(map.erase(3)); // Key not found. + + EXPECT_TRUE(map.empty()); + EXPECT_TRUE(map.dynamic()); + } +} + } // namespace android::test -- cgit v1.2.3-59-g8ed1b From 756005bf3505ac83c048651aa9c15406bbd2d692 Mon Sep 17 00:00:00 2001 From: rnlee Date: Thu, 27 May 2021 10:46:36 -0700 Subject: Use skia to draw pre-rotated RefreshRateOverlay. Bug: 166793515 Test: Manual with adb shell dumpsys SurfaceFlinger | grep -A 30 "HWC layers" Change-Id: I6aad5730794fdb2ca6e0575e650402939bbd24cc --- services/surfaceflinger/RefreshRateOverlay.cpp | 169 ++++++++++++--------- services/surfaceflinger/RefreshRateOverlay.h | 24 +-- services/surfaceflinger/tests/unittests/Android.bp | 5 +- .../mock/DisplayHardware/MockComposer.cpp | 1 + 4 files changed, 112 insertions(+), 87 deletions(-) diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index a9fd16cb75..075d0eb1dc 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -25,6 +25,10 @@ #include "Client.h" #include "Layer.h" +#include +#include +#include +#include #include #undef LOG_TAG @@ -32,85 +36,64 @@ namespace android { -void RefreshRateOverlay::SevenSegmentDrawer::drawRect(const Rect& r, const half4& color, - const sp& buffer, - uint8_t* pixels) { - for (int32_t j = r.top; j < r.bottom; j++) { - if (j >= buffer->getHeight()) { - break; - } - - for (int32_t i = r.left; i < r.right; i++) { - if (i >= buffer->getWidth()) { - break; - } - - uint8_t* iter = pixels + 4 * (i + (buffer->getStride() * j)); - iter[0] = uint8_t(color.r * 255); - iter[1] = uint8_t(color.g * 255); - iter[2] = uint8_t(color.b * 255); - iter[3] = uint8_t(color.a * 255); - } - } -} - -void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, - const half4& color, - const sp& buffer, - uint8_t* pixels) { - const Rect rect = [&]() { +void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, SkColor& color, + SkCanvas& canvas) { + const SkRect rect = [&]() { switch (segment) { case Segment::Upper: - return Rect(left, 0, left + DIGIT_WIDTH, DIGIT_SPACE); + return SkRect::MakeLTRB(left, 0, left + DIGIT_WIDTH, DIGIT_SPACE); case Segment::UpperLeft: - return Rect(left, 0, left + DIGIT_SPACE, DIGIT_HEIGHT / 2); + return SkRect::MakeLTRB(left, 0, left + DIGIT_SPACE, DIGIT_HEIGHT / 2); case Segment::UpperRight: - return Rect(left + DIGIT_WIDTH - DIGIT_SPACE, 0, left + DIGIT_WIDTH, - DIGIT_HEIGHT / 2); + return SkRect::MakeLTRB(left + DIGIT_WIDTH - DIGIT_SPACE, 0, left + DIGIT_WIDTH, + DIGIT_HEIGHT / 2); case Segment::Middle: - return Rect(left, DIGIT_HEIGHT / 2 - DIGIT_SPACE / 2, left + DIGIT_WIDTH, - DIGIT_HEIGHT / 2 + DIGIT_SPACE / 2); + return SkRect::MakeLTRB(left, DIGIT_HEIGHT / 2 - DIGIT_SPACE / 2, + left + DIGIT_WIDTH, DIGIT_HEIGHT / 2 + DIGIT_SPACE / 2); case Segment::LowerLeft: - return Rect(left, DIGIT_HEIGHT / 2, left + DIGIT_SPACE, DIGIT_HEIGHT); + return SkRect::MakeLTRB(left, DIGIT_HEIGHT / 2, left + DIGIT_SPACE, DIGIT_HEIGHT); case Segment::LowerRight: - return Rect(left + DIGIT_WIDTH - DIGIT_SPACE, DIGIT_HEIGHT / 2, left + DIGIT_WIDTH, - DIGIT_HEIGHT); - case Segment::Buttom: - return Rect(left, DIGIT_HEIGHT - DIGIT_SPACE, left + DIGIT_WIDTH, DIGIT_HEIGHT); + return SkRect::MakeLTRB(left + DIGIT_WIDTH - DIGIT_SPACE, DIGIT_HEIGHT / 2, + left + DIGIT_WIDTH, DIGIT_HEIGHT); + case Segment::Bottom: + return SkRect::MakeLTRB(left, DIGIT_HEIGHT - DIGIT_SPACE, left + DIGIT_WIDTH, + DIGIT_HEIGHT); } }(); - drawRect(rect, color, buffer, pixels); + SkPaint paint; + paint.setColor(color); + paint.setBlendMode(SkBlendMode::kSrc); + canvas.drawRect(rect, paint); } -void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, const half4& color, - const sp& buffer, - uint8_t* pixels) { +void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, SkColor& color, + SkCanvas& canvas) { if (digit < 0 || digit > 9) return; if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 7 || digit == 8 || digit == 9) - drawSegment(Segment::Upper, left, color, buffer, pixels); + drawSegment(Segment::Upper, left, color, canvas); if (digit == 0 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9) - drawSegment(Segment::UpperLeft, left, color, buffer, pixels); + drawSegment(Segment::UpperLeft, left, color, canvas); if (digit == 0 || digit == 1 || digit == 2 || digit == 3 || digit == 4 || digit == 7 || digit == 8 || digit == 9) - drawSegment(Segment::UpperRight, left, color, buffer, pixels); + drawSegment(Segment::UpperRight, left, color, canvas); if (digit == 2 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9) - drawSegment(Segment::Middle, left, color, buffer, pixels); + drawSegment(Segment::Middle, left, color, canvas); if (digit == 0 || digit == 2 || digit == 6 || digit == 8) - drawSegment(Segment::LowerLeft, left, color, buffer, pixels); + drawSegment(Segment::LowerLeft, left, color, canvas); if (digit == 0 || digit == 1 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 7 || digit == 8 || digit == 9) - drawSegment(Segment::LowerRight, left, color, buffer, pixels); + drawSegment(Segment::LowerRight, left, color, canvas); if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 8 || digit == 9) - drawSegment(Segment::Buttom, left, color, buffer, pixels); + drawSegment(Segment::Bottom, left, color, canvas); } -std::vector> RefreshRateOverlay::SevenSegmentDrawer::drawNumber( - int number, const half4& color, bool showSpinner) { +std::vector> RefreshRateOverlay::SevenSegmentDrawer::draw( + int number, SkColor& color, ui::Transform::RotationFlags rotation, bool showSpinner) { if (number < 0 || number > 1000) return {}; const auto hundreds = number / 100; @@ -120,55 +103,76 @@ std::vector> RefreshRateOverlay::SevenSegmentDrawer::drawNumbe std::vector> buffers; const auto loopCount = showSpinner ? 6 : 1; for (int i = 0; i < loopCount; i++) { + // Pre-rotate the buffer before it reaches SurfaceFlinger. + SkMatrix canvasTransform = SkMatrix(); + auto [bufferWidth, bufferHeight] = [&] { + switch (rotation) { + case ui::Transform::ROT_90: + canvasTransform.setTranslate(BUFFER_HEIGHT, 0); + canvasTransform.preRotate(90); + return std::make_tuple(BUFFER_HEIGHT, BUFFER_WIDTH); + case ui::Transform::ROT_270: + canvasTransform.setRotate(270, BUFFER_WIDTH / 2.0, BUFFER_WIDTH / 2.0); + return std::make_tuple(BUFFER_HEIGHT, BUFFER_WIDTH); + default: + return std::make_tuple(BUFFER_WIDTH, BUFFER_HEIGHT); + } + }(); sp buffer = - new GraphicBuffer(BUFFER_WIDTH, BUFFER_HEIGHT, HAL_PIXEL_FORMAT_RGBA_8888, 1, + new GraphicBuffer(bufferWidth, bufferHeight, HAL_PIXEL_FORMAT_RGBA_8888, 1, GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_TEXTURE, "RefreshRateOverlayBuffer"); const status_t bufferStatus = buffer->initCheck(); LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d", bufferStatus); - uint8_t* pixels; - buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast(&pixels)); - // Clear buffer content - drawRect(Rect(BUFFER_WIDTH, BUFFER_HEIGHT), half4(0), buffer, pixels); + + sk_sp surface = SkSurface::MakeRasterN32Premul(bufferWidth, bufferHeight); + SkCanvas* canvas = surface->getCanvas(); + canvas->setMatrix(canvasTransform); + int left = 0; if (hundreds != 0) { - drawDigit(hundreds, left, color, buffer, pixels); + drawDigit(hundreds, left, color, *canvas); } left += DIGIT_WIDTH + DIGIT_SPACE; if (tens != 0) { - drawDigit(tens, left, color, buffer, pixels); + drawDigit(tens, left, color, *canvas); } left += DIGIT_WIDTH + DIGIT_SPACE; - drawDigit(ones, left, color, buffer, pixels); + drawDigit(ones, left, color, *canvas); left += DIGIT_WIDTH + DIGIT_SPACE; if (showSpinner) { switch (i) { case 0: - drawSegment(Segment::Upper, left, color, buffer, pixels); + drawSegment(Segment::Upper, left, color, *canvas); break; case 1: - drawSegment(Segment::UpperRight, left, color, buffer, pixels); + drawSegment(Segment::UpperRight, left, color, *canvas); break; case 2: - drawSegment(Segment::LowerRight, left, color, buffer, pixels); + drawSegment(Segment::LowerRight, left, color, *canvas); break; case 3: - drawSegment(Segment::Buttom, left, color, buffer, pixels); + drawSegment(Segment::Bottom, left, color, *canvas); break; case 4: - drawSegment(Segment::LowerLeft, left, color, buffer, pixels); + drawSegment(Segment::LowerLeft, left, color, *canvas); break; case 5: - drawSegment(Segment::UpperLeft, left, color, buffer, pixels); + drawSegment(Segment::UpperLeft, left, color, *canvas); break; } } + void* pixels = nullptr; + buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast(&pixels)); + const SkImageInfo& imageInfo = surface->imageInfo(); + size_t dstRowBytes = buffer->getStride() * imageInfo.bytesPerPixel(); + canvas->readPixels(imageInfo, pixels, dstRowBytes, 0, 0); buffer->unlock(); buffers.emplace_back(buffer); } @@ -210,7 +214,22 @@ bool RefreshRateOverlay::createLayer() { const std::vector>& RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) { - if (mBufferCache.find(fps) == mBufferCache.end()) { + ui::Transform::RotationFlags transformHint = mLayer->getTransformHint(); + // Tell SurfaceFlinger about the pre-rotation on the buffer. + const auto transform = [&] { + switch (transformHint) { + case ui::Transform::ROT_90: + return ui::Transform::ROT_270; + case ui::Transform::ROT_270: + return ui::Transform::ROT_90; + default: + return ui::Transform::ROT_0; + } + }(); + mLayer->setTransform(transform); + + if (mBufferCache.find(transformHint) == mBufferCache.end() || + mBufferCache.at(transformHint).find(fps) == mBufferCache.at(transformHint).end()) { // Ensure the range is > 0, so we don't divide by 0. const auto rangeLength = std::max(1u, mHighFps - mLowFps); // Clip values outside the range [mLowFps, mHighFps]. The current fps may be outside @@ -218,12 +237,14 @@ RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) { fps = std::max(fps, mLowFps); fps = std::min(fps, mHighFps); const auto fpsScale = static_cast(fps - mLowFps) / rangeLength; - half4 color; - color.r = HIGH_FPS_COLOR.r * fpsScale + LOW_FPS_COLOR.r * (1 - fpsScale); - color.g = HIGH_FPS_COLOR.g * fpsScale + LOW_FPS_COLOR.g * (1 - fpsScale); - color.b = HIGH_FPS_COLOR.b * fpsScale + LOW_FPS_COLOR.b * (1 - fpsScale); - color.a = ALPHA; - auto buffers = SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner); + SkColor4f colorBase = SkColor4f::FromColor(HIGH_FPS_COLOR) * fpsScale; + SkColor4f lowFpsColor = SkColor4f::FromColor(LOW_FPS_COLOR) * (1 - fpsScale); + colorBase.fR = colorBase.fR + lowFpsColor.fR; + colorBase.fG = colorBase.fG + lowFpsColor.fG; + colorBase.fB = colorBase.fB + lowFpsColor.fB; + colorBase.fA = ALPHA; + SkColor color = colorBase.toSkColor(); + auto buffers = SevenSegmentDrawer::draw(fps, color, transformHint, mShowSpinner); std::vector> textures; std::transform(buffers.begin(), buffers.end(), std::back_inserter(textures), [&](const auto& buffer) -> std::shared_ptr { @@ -233,10 +254,10 @@ RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) { renderengine::ExternalTexture:: Usage::READABLE); }); - mBufferCache.emplace(fps, textures); + mBufferCache[transformHint].emplace(fps, textures); } - return mBufferCache[fps]; + return mBufferCache[transformHint][fps]; } void RefreshRateOverlay::setViewport(ui::Size viewport) { diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h index aa8329c46a..cb8b2271da 100644 --- a/services/surfaceflinger/RefreshRateOverlay.h +++ b/services/surfaceflinger/RefreshRateOverlay.h @@ -22,6 +22,8 @@ #include #include +#include +#include #include #include "Fps.h" @@ -47,20 +49,16 @@ public: private: class SevenSegmentDrawer { public: - static std::vector> drawNumber(int number, const half4& color, - bool showSpinner); + static std::vector> draw(int number, SkColor& color, + ui::Transform::RotationFlags, bool showSpinner); static uint32_t getHeight() { return BUFFER_HEIGHT; } static uint32_t getWidth() { return BUFFER_WIDTH; } private: - enum class Segment { Upper, UpperLeft, UpperRight, Middle, LowerLeft, LowerRight, Buttom }; + enum class Segment { Upper, UpperLeft, UpperRight, Middle, LowerLeft, LowerRight, Bottom }; - static void drawRect(const Rect& r, const half4& color, const sp& buffer, - uint8_t* pixels); - static void drawSegment(Segment segment, int left, const half4& color, - const sp& buffer, uint8_t* pixels); - static void drawDigit(int digit, int left, const half4& color, - const sp& buffer, uint8_t* pixels); + static void drawSegment(Segment segment, int left, SkColor& color, SkCanvas& canvas); + static void drawDigit(int digit, int left, SkColor& color, SkCanvas& canvas); static constexpr uint32_t DIGIT_HEIGHT = 100; static constexpr uint32_t DIGIT_WIDTH = 64; @@ -80,13 +78,15 @@ private: sp mIBinder; sp mGbp; - std::unordered_map>> + std::unordered_map< + ui::Transform::RotationFlags, + std::unordered_map>>> mBufferCache; std::optional mCurrentFps; int mFrame = 0; static constexpr float ALPHA = 0.8f; - const half3 LOW_FPS_COLOR = half3(1.0f, 0.0f, 0.0f); - const half3 HIGH_FPS_COLOR = half3(0.0f, 1.0f, 0.0f); + const SkColor LOW_FPS_COLOR = SK_ColorRED; + const SkColor HIGH_FPS_COLOR = SK_ColorGREEN; const bool mShowSpinner; diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 7512fd3dfe..69c99a8aeb 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -23,7 +23,10 @@ package { cc_test { name: "libsurfaceflinger_unittest", - defaults: ["surfaceflinger_defaults"], + defaults: [ + "skia_renderengine_deps", + "surfaceflinger_defaults", + ], test_suites: ["device-tests"], sanitize: { // Using the address sanitizer not only helps uncover issues in the code diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp index 7de187207e..20d41e6072 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp @@ -18,6 +18,7 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#undef LOG_TAG #define LOG_TAG "MockComposer" #include "mock/DisplayHardware/MockComposer.h" -- cgit v1.2.3-59-g8ed1b From 4188ffdbcf068eced5b64f77e96da96ee64de7e2 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Sun, 7 Feb 2021 22:15:44 -0800 Subject: FTL: Add to_chars Wrap std::to_chars for a slightly faster alternative to std::to_string with optional radix. The upcoming ftl/{enum.h,flags.h} imported from IF will use the binary/ hex options, while SF will stringify display IDs for trace labels using the non-allocating version. Bug: 185536303 Test: ftl_test Change-Id: I587622763303d2baeb844e52eff55ce8f0bcbf1e --- include/ftl/string.h | 101 +++++++++++++++++++++++++ libs/ftl/Android.bp | 1 + libs/ftl/string_test.cpp | 187 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 include/ftl/string.h create mode 100644 libs/ftl/string_test.cpp diff --git a/include/ftl/string.h b/include/ftl/string.h new file mode 100644 index 0000000000..2d96b06a2f --- /dev/null +++ b/include/ftl/string.h @@ -0,0 +1,101 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace android::ftl { + +enum class Radix { kBin = 2, kDec = 10, kHex = 16 }; + +template +struct to_chars_length { + static_assert(std::is_integral_v); + // Maximum binary digits, plus minus sign and radix prefix. + static constexpr std::size_t value = std::numeric_limits>::digits + 3; +}; + +template +constexpr std::size_t to_chars_length_v = to_chars_length::value; + +template +using to_chars_buffer_t = char[to_chars_length_v]; + +// Lightweight (not allocating nor sprintf-based) alternative to std::to_string for integers, with +// optional radix. See also ftl::to_string below. +// +// ftl::to_chars_buffer_t<> buffer; +// +// assert(ftl::to_chars(buffer, 123u) == "123"); +// assert(ftl::to_chars(buffer, -42, ftl::Radix::kBin) == "-0b101010"); +// assert(ftl::to_chars(buffer, 0xcafe, ftl::Radix::kHex) == "0xcafe"); +// assert(ftl::to_chars(buffer, '*', ftl::Radix::kHex) == "0x2a"); +// +template +std::string_view to_chars(char (&buffer)[N], T v, Radix radix = Radix::kDec) { + static_assert(N >= to_chars_length_v); + + auto begin = buffer + 2; + const auto [end, err] = std::to_chars(begin, buffer + N, v, static_cast(radix)); + assert(err == std::errc()); + + if (radix == Radix::kDec) { + // TODO: Replace with {begin, end} in C++20. + return {begin, static_cast(end - begin)}; + } + + const auto prefix = radix == Radix::kBin ? 'b' : 'x'; + if constexpr (std::is_unsigned_v) { + buffer[0] = '0'; + buffer[1] = prefix; + } else { + if (*begin == '-') { + *buffer = '-'; + } else { + --begin; + } + + *begin-- = prefix; + *begin = '0'; + } + + // TODO: Replace with {buffer, end} in C++20. + return {buffer, static_cast(end - buffer)}; +} + +// Lightweight (not sprintf-based) alternative to std::to_string for integers, with optional radix. +// +// assert(ftl::to_string(123u) == "123"); +// assert(ftl::to_string(-42, ftl::Radix::kBin) == "-0b101010"); +// assert(ftl::to_string(0xcafe, ftl::Radix::kHex) == "0xcafe"); +// assert(ftl::to_string('*', ftl::Radix::kHex) == "0x2a"); +// +template +inline std::string to_string(T v, Radix radix = Radix::kDec) { + to_chars_buffer_t buffer; + return std::string(to_chars(buffer, v, radix)); +} + +std::string to_string(bool) = delete; +std::string to_string(bool, Radix) = delete; + +} // namespace android::ftl diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 97626bec7d..4226e32ee7 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -18,6 +18,7 @@ cc_test { "small_map_test.cpp", "small_vector_test.cpp", "static_vector_test.cpp", + "string_test.cpp", ], cflags: [ "-Wall", diff --git a/libs/ftl/string_test.cpp b/libs/ftl/string_test.cpp new file mode 100644 index 0000000000..f3d85c8319 --- /dev/null +++ b/libs/ftl/string_test.cpp @@ -0,0 +1,187 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace android::test { + +// Keep in sync with example usage in header file. +TEST(String, ToChars) { + ftl::to_chars_buffer_t<> buffer; + + EXPECT_EQ(ftl::to_chars(buffer, 123u), "123"); + EXPECT_EQ(ftl::to_chars(buffer, -42, ftl::Radix::kBin), "-0b101010"); + EXPECT_EQ(ftl::to_chars(buffer, 0xcafe, ftl::Radix::kHex), "0xcafe"); + EXPECT_EQ(ftl::to_chars(buffer, '*', ftl::Radix::kHex), "0x2a"); +} + +namespace { + +template +void ToCharsTest() { + constexpr auto kRadix = F::kRadix; + + using Limits = std::numeric_limits; + constexpr auto kMin = Limits::min(); + constexpr auto kMax = Limits::max(); + constexpr auto kNeg = static_cast(-42); + constexpr auto kPos = static_cast(123); + + ftl::to_chars_buffer_t buffer; + + EXPECT_EQ(ftl::to_chars(buffer, kMin, kRadix), F{}(kMin)); + EXPECT_EQ(ftl::to_chars(buffer, kMax, kRadix), F{}(kMax)); + EXPECT_EQ(ftl::to_chars(buffer, kNeg, kRadix), F{}(kNeg)); + EXPECT_EQ(ftl::to_chars(buffer, kPos, kRadix), F{}(kPos)); +} + +template +struct Types {}; + +template +struct ToCharsTests; + +template +struct ToCharsTests> { + static void test() { + ToCharsTest(); + ToCharsTests>::test(); + } +}; + +template +struct ToCharsTests> { + static void test() {} +}; + +template > +U to_unsigned(std::ostream& stream, T v) { + if (std::is_same_v) return v; + + if (v < 0) { + stream << '-'; + return std::numeric_limits::max() - static_cast(v) + 1; + } else { + return static_cast(v); + } +} + +struct Bin { + static constexpr auto kRadix = ftl::Radix::kBin; + + template + std::string operator()(T v) const { + std::ostringstream stream; + auto u = to_unsigned(stream, v); + stream << "0b"; + + if (u == 0) { + stream << 0; + } else { + std::ostringstream digits; + do { + digits << (u & 1); + } while (u >>= 1); + + const auto str = digits.str(); + std::copy(str.rbegin(), str.rend(), std::ostream_iterator(stream)); + } + + return stream.str(); + } +}; + +struct Dec { + static constexpr auto kRadix = ftl::Radix::kDec; + + template + std::string operator()(T v) const { + return std::to_string(v); + } +}; + +struct Hex { + static constexpr auto kRadix = ftl::Radix::kHex; + + template + std::string operator()(T v) const { + std::ostringstream stream; + const auto u = to_unsigned(stream, v); + stream << "0x" << std::hex << std::nouppercase; + stream << (sizeof(T) == 1 ? static_cast(u) : u); + return stream.str(); + } +}; + +using IntegerTypes = + Types; + +} // namespace + +TEST(String, ToCharsBin) { + ToCharsTests::test(); + + { + const std::uint8_t x = 0b1111'1111; + ftl::to_chars_buffer_t buffer; + EXPECT_EQ(ftl::to_chars(buffer, x, ftl::Radix::kBin), "0b11111111"); + } + { + const std::int16_t x = -0b1000'0000'0000'0000; + ftl::to_chars_buffer_t buffer; + EXPECT_EQ(ftl::to_chars(buffer, x, ftl::Radix::kBin), "-0b1000000000000000"); + } +} + +TEST(String, ToCharsDec) { + ToCharsTests::test(); + + { + const std::uint32_t x = UINT32_MAX; + ftl::to_chars_buffer_t buffer; + EXPECT_EQ(ftl::to_chars(buffer, x), "4294967295"); + } + { + const std::int32_t x = INT32_MIN; + ftl::to_chars_buffer_t buffer; + EXPECT_EQ(ftl::to_chars(buffer, x), "-2147483648"); + } +} + +TEST(String, ToCharsHex) { + ToCharsTests::test(); + + { + const std::uint16_t x = 0xfade; + ftl::to_chars_buffer_t buffer; + EXPECT_EQ(ftl::to_chars(buffer, x, ftl::Radix::kHex), "0xfade"); + } + { + ftl::to_chars_buffer_t<> buffer; + EXPECT_EQ(ftl::to_chars(buffer, INT64_MIN, ftl::Radix::kHex), "-0x8000000000000000"); + } +} + +} // namespace android::test -- cgit v1.2.3-59-g8ed1b From 9f5e5dbcb31032fc729501805ed548d80abad115 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Tue, 25 May 2021 12:52:24 -0700 Subject: FTL: Add cast safety checker Add a function to check cast safety, to be used by a saturating cast that (among other uses) will replace ui::Size::clamp, which invokes the undefined behavior of signed overflow when casting INT32_MAX to float and back. Bug: 185536303 Test: ftl_test Change-Id: I412a1d72de7235b73ea3dd3f194d0da178ce5eb2 --- include/ftl/cast.h | 84 +++++++++++++++++++ include/ftl/details/cast.h | 57 +++++++++++++ libs/ftl/Android.bp | 1 + libs/ftl/cast_test.cpp | 200 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 342 insertions(+) create mode 100644 include/ftl/cast.h create mode 100644 include/ftl/details/cast.h create mode 100644 libs/ftl/cast_test.cpp diff --git a/include/ftl/cast.h b/include/ftl/cast.h new file mode 100644 index 0000000000..ff1b58ad56 --- /dev/null +++ b/include/ftl/cast.h @@ -0,0 +1,84 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +namespace android::ftl { + +enum class CastSafety { kSafe, kUnderflow, kOverflow }; + +// Returns whether static_cast(v) is safe, or would result in underflow or overflow. +// +// static_assert(ftl::cast_safety(-1) == ftl::CastSafety::kUnderflow); +// static_assert(ftl::cast_safety(128u) == ftl::CastSafety::kOverflow); +// +// static_assert(ftl::cast_safety(-.1f) == ftl::CastSafety::kUnderflow); +// static_assert(ftl::cast_safety(static_cast(INT32_MAX)) == +// ftl::CastSafety::kOverflow); +// +// static_assert(ftl::cast_safety(-DBL_MAX) == ftl::CastSafety::kUnderflow); +// +template +constexpr CastSafety cast_safety(T v) { + static_assert(std::is_arithmetic_v); + static_assert(std::is_arithmetic_v); + + constexpr bool kFromSigned = std::is_signed_v; + constexpr bool kToSigned = std::is_signed_v; + + using details::max_exponent; + + // If the R range contains the T range, then casting is always safe. + if constexpr ((kFromSigned == kToSigned && max_exponent >= max_exponent) || + (!kFromSigned && kToSigned && max_exponent > max_exponent)) { + return CastSafety::kSafe; + } + + using C = std::common_type_t; + + if constexpr (kFromSigned) { + using L = details::safe_limits; + + if constexpr (kToSigned) { + // Signed to signed. + if (v < L::lowest()) return CastSafety::kUnderflow; + return v <= L::max() ? CastSafety::kSafe : CastSafety::kOverflow; + } else { + // Signed to unsigned. + if (v < 0) return CastSafety::kUnderflow; + return static_cast(v) <= static_cast(L::max()) ? CastSafety::kSafe + : CastSafety::kOverflow; + } + } else { + using L = std::numeric_limits; + + if constexpr (kToSigned) { + // Unsigned to signed. + return static_cast(v) <= static_cast(L::max()) ? CastSafety::kSafe + : CastSafety::kOverflow; + } else { + // Unsigned to unsigned. + return v <= L::max() ? CastSafety::kSafe : CastSafety::kOverflow; + } + } +} + +} // namespace android::ftl diff --git a/include/ftl/details/cast.h b/include/ftl/details/cast.h new file mode 100644 index 0000000000..87b9f1e20a --- /dev/null +++ b/include/ftl/details/cast.h @@ -0,0 +1,57 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace android::ftl::details { + +// Exponent whose power of 2 is the (exclusive) upper bound of T. +template > +constexpr int max_exponent = std::is_floating_point_v ? L::max_exponent : L::digits; + +// Extension of std::numeric_limits that reduces the maximum for integral types T such that it +// has an exact representation for floating-point types F. For example, the maximum int32_t value +// is 2'147'483'647, but casting it to float commonly rounds up to 2'147'483'650.f, which cannot +// be safely converted back lest the signed overflow invokes undefined behavior. This pitfall is +// avoided by clearing the lower (31 - 24 =) 7 bits of precision to 2'147'483'520. Note that the +// minimum is representable. +template +struct safe_limits : std::numeric_limits { + static constexpr T max() { + using Base = std::numeric_limits; + + if constexpr (std::is_integral_v && std::is_floating_point_v) { + // Assume the mantissa is 24 bits for float, or 53 bits for double. + using Float = std::numeric_limits; + static_assert(Float::is_iec559); + + // If the integer is wider than the mantissa, clear the excess bits of precision. + constexpr int kShift = Base::digits - Float::digits; + if constexpr (kShift > 0) { + using U = std::make_unsigned_t; + constexpr U kOne = static_cast(1); + return static_cast(Base::max()) & ~((kOne << kShift) - kOne); + } + } + + return Base::max(); + } +}; + +} // namespace android::ftl::details diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 97626bec7d..22267912b9 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -14,6 +14,7 @@ cc_test { address: true, }, srcs: [ + "cast_test.cpp", "future_test.cpp", "small_map_test.cpp", "small_vector_test.cpp", diff --git a/libs/ftl/cast_test.cpp b/libs/ftl/cast_test.cpp new file mode 100644 index 0000000000..2abcb8fe66 --- /dev/null +++ b/libs/ftl/cast_test.cpp @@ -0,0 +1,200 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include + +namespace android::test { + +using ftl::cast_safety; +using ftl::CastSafety; + +template +constexpr T min = std::numeric_limits::lowest(); + +template +constexpr T max = std::numeric_limits::max(); + +template +constexpr T inf = std::numeric_limits::infinity(); + +template +constexpr T NaN = std::numeric_limits::quiet_NaN(); + +// Keep in sync with example usage in header file. + +static_assert(cast_safety(-1) == CastSafety::kUnderflow); +static_assert(cast_safety(128u) == CastSafety::kOverflow); + +static_assert(cast_safety(-.1f) == CastSafety::kUnderflow); +static_assert(cast_safety(static_cast(INT32_MAX)) == CastSafety::kOverflow); + +static_assert(cast_safety(-DBL_MAX) == CastSafety::kUnderflow); + +// Unsigned to unsigned. + +static_assert(cast_safety(0u) == CastSafety::kSafe); +static_assert(cast_safety(max) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); + +static_assert(cast_safety(max) == CastSafety::kOverflow); +static_assert(cast_safety(static_cast(max) + 1) == + CastSafety::kOverflow); + +// Unsigned to signed. + +static_assert(cast_safety(0u) == CastSafety::kSafe); +static_assert(cast_safety(max) == CastSafety::kSafe); +static_assert(cast_safety(max) == CastSafety::kOverflow); + +static_assert(cast_safety(static_cast(max) - 1) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max) + 1) == + CastSafety::kOverflow); + +// Signed to unsigned. + +static_assert(cast_safety(0) == CastSafety::kSafe); +static_assert(cast_safety(max) == CastSafety::kSafe); +static_assert(cast_safety(max) == CastSafety::kSafe); + +static_assert(cast_safety(-1) == CastSafety::kUnderflow); +static_assert(cast_safety(max) == CastSafety::kOverflow); + +static_assert(cast_safety(static_cast(max) - 1) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max) + 1) == + CastSafety::kOverflow); + +// Signed to signed. + +static_assert(cast_safety(-129) == CastSafety::kUnderflow); +static_assert(cast_safety(-128) == CastSafety::kSafe); +static_assert(cast_safety(127) == CastSafety::kSafe); +static_assert(cast_safety(128) == CastSafety::kOverflow); + +static_assert(cast_safety(static_cast(min)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); + +static_assert(cast_safety(min) == CastSafety::kUnderflow); +static_assert(cast_safety(max) == CastSafety::kOverflow); + +// Float to float. + +static_assert(cast_safety(max) == CastSafety::kSafe); +static_assert(cast_safety(min) == CastSafety::kSafe); + +static_assert(cast_safety(min) == CastSafety::kUnderflow); +static_assert(cast_safety(max) == CastSafety::kOverflow); + +TEST(CastSafety, FloatToFloat) { + EXPECT_EQ(cast_safety(std::nexttoward(static_cast(min), min)), + CastSafety::kUnderflow); + EXPECT_EQ(cast_safety(std::nexttoward(static_cast(max), max)), + CastSafety::kOverflow); +} + +// Unsigned to float. + +static_assert(cast_safety(0u) == CastSafety::kSafe); +static_assert(cast_safety(max) == CastSafety::kSafe); + +static_assert(cast_safety(0u) == CastSafety::kSafe); +static_assert(cast_safety(max) == CastSafety::kSafe); + +// Signed to float. + +static_assert(cast_safety(min) == CastSafety::kSafe); +static_assert(cast_safety(max) == CastSafety::kSafe); + +static_assert(cast_safety(min) == CastSafety::kSafe); +static_assert(cast_safety(max) == CastSafety::kSafe); + +// Float to unsigned. + +static_assert(cast_safety(0.f) == CastSafety::kSafe); +static_assert(cast_safety(min) == CastSafety::kUnderflow); +static_assert(cast_safety(max) == CastSafety::kOverflow); +static_assert(cast_safety(-.1f) == CastSafety::kUnderflow); + +static_assert(cast_safety(-inf) == CastSafety::kUnderflow); +static_assert(cast_safety(inf) == CastSafety::kOverflow); +static_assert(cast_safety(NaN) == CastSafety::kOverflow); + +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kOverflow); +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); + +static_assert(cast_safety(0.0) == CastSafety::kSafe); +static_assert(cast_safety(min) == CastSafety::kUnderflow); +static_assert(cast_safety(max) == CastSafety::kOverflow); +static_assert(cast_safety(-.1) == CastSafety::kUnderflow); + +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kOverflow); +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kOverflow); + +// Float to signed. + +static_assert(cast_safety(0.f) == CastSafety::kSafe); +static_assert(cast_safety(min) == CastSafety::kUnderflow); +static_assert(cast_safety(max) == CastSafety::kOverflow); + +static_assert(cast_safety(-inf) == CastSafety::kUnderflow); +static_assert(cast_safety(inf) == CastSafety::kOverflow); +static_assert(cast_safety(NaN) == CastSafety::kOverflow); + +static_assert(cast_safety(static_cast(min)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kOverflow); +static_assert(cast_safety(static_cast(min)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); + +static_assert(cast_safety(0.0) == CastSafety::kSafe); +static_assert(cast_safety(min) == CastSafety::kUnderflow); +static_assert(cast_safety(max) == CastSafety::kOverflow); + +static_assert(cast_safety(static_cast(min)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kOverflow); +static_assert(cast_safety(static_cast(min)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kOverflow); + +TEST(CastSafety, FloatToSigned) { + constexpr int32_t kMax = ftl::details::safe_limits::max(); + static_assert(kMax == 2'147'483'520); + EXPECT_EQ(kMax, static_cast(std::nexttowardf(max, 0))); + + EXPECT_EQ(cast_safety(std::nexttowardf(min, 0)), CastSafety::kSafe); + EXPECT_EQ(cast_safety(std::nexttowardf(max, 0)), CastSafety::kSafe); + EXPECT_EQ(cast_safety(std::nexttoward(min, 0)), CastSafety::kSafe); + EXPECT_EQ(cast_safety(std::nexttoward(max, 0)), CastSafety::kSafe); + + EXPECT_EQ(cast_safety(std::nexttowardf(min, min)), + CastSafety::kUnderflow); + EXPECT_EQ(cast_safety(std::nexttowardf(max, max)), + CastSafety::kOverflow); + EXPECT_EQ(cast_safety(std::nexttoward(min, min)), + CastSafety::kUnderflow); + EXPECT_EQ(cast_safety(std::nexttoward(max, max)), + CastSafety::kOverflow); +} + +} // namespace android::test -- cgit v1.2.3-59-g8ed1b From 1a48fab10b3b5b9ab9bfb3c5166d72843e861535 Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Wed, 9 Jun 2021 11:21:40 +0530 Subject: Fix for FWR SF crash bug:176224224 Test: Stress test Change-Id: I89110a28c27ebc66f28466b61bf99ef0c4c3437d --- services/surfaceflinger/BufferQueueLayer.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index e7f373ff3f..2f2e6731fe 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -125,11 +125,11 @@ bool BufferQueueLayer::isBufferDue(nsecs_t expectedPresentTime) const { // ----------------------------------------------------------------------- bool BufferQueueLayer::fenceHasSignaled() const { + Mutex::Autolock lock(mQueueItemLock); if (!hasFrameUpdate()) { return true; } - Mutex::Autolock lock(mQueueItemLock); if (mQueueItems[0].item.mIsDroppable) { // Even though this buffer's fence may not have signaled yet, it could // be replaced by another buffer before it has a chance to, which means @@ -148,11 +148,12 @@ bool BufferQueueLayer::fenceHasSignaled() const { } bool BufferQueueLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const { + Mutex::Autolock lock(mQueueItemLock); + if (!hasFrameUpdate() || isRemovedFromCurrentState()) { return true; } - Mutex::Autolock lock(mQueueItemLock); return mQueueItems[0].item.mTimestamp <= expectedPresentTime; } @@ -264,13 +265,15 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t // and return early if (queuedBuffer) { Mutex::Autolock lock(mQueueItemLock); - mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage); - mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber); - if (mQueueItems[0].surfaceFrame) { - addSurfaceFrameDroppedForBuffer(mQueueItems[0].surfaceFrame); + if (mQueuedFrames > 0) { + mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage); + mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber); + if (mQueueItems[0].surfaceFrame) { + addSurfaceFrameDroppedForBuffer(mQueueItems[0].surfaceFrame); + } + mQueueItems.erase(mQueueItems.begin()); + mQueuedFrames--; } - mQueueItems.erase(mQueueItems.begin()); - mQueuedFrames--; } return BAD_VALUE; } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) { @@ -300,6 +303,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t return BAD_VALUE; } + bool more_frames_pending = false; if (queuedBuffer) { // Autolock scope auto currentFrameNumber = mConsumer->getFrameNumber(); @@ -308,7 +312,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t // Remove any stale buffers that have been dropped during // updateTexImage - while (mQueueItems[0].item.mFrameNumber != currentFrameNumber) { + while (mQueuedFrames > 0 && mQueueItems[0].item.mFrameNumber != currentFrameNumber) { mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage); mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber); if (mQueueItems[0].surfaceFrame) { @@ -329,11 +333,12 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime); } mQueueItems.erase(mQueueItems.begin()); + more_frames_pending = (mQueuedFrames.fetch_sub(1) > 1); } // Decrement the queued-frames count. Signal another event if we // have more frames pending. - if ((queuedBuffer && mQueuedFrames.fetch_sub(1) > 1) || mAutoRefresh) { + if ((queuedBuffer && more_frames_pending) || mAutoRefresh) { mFlinger->signalLayerUpdate(); } -- cgit v1.2.3-59-g8ed1b From 64452933360cf0eee7fb3ba0eb2c69ccb8af09e3 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 6 Nov 2020 17:51:32 -0600 Subject: Remove portalToDisplay functionality There should not be any more users of the portal to display functionality. We can now delete this unused code. Bug: 167946720 Test: atest inputflinger_tests Change-Id: I9e9a2e7d6c3e5d5fe969ae6207f7c1f2db169f04 --- .../inputflinger/dispatcher/InputDispatcher.cpp | 73 ++++------------------ services/inputflinger/dispatcher/InputDispatcher.h | 4 +- services/inputflinger/dispatcher/TouchState.cpp | 13 ---- services/inputflinger/dispatcher/TouchState.h | 5 -- 4 files changed, 13 insertions(+), 82 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 15c810db5f..43a861e126 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -900,8 +900,7 @@ bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEnt } // Alternatively, maybe there's a gesture monitor that could handle this event - std::vector gestureMonitors = - findTouchedGestureMonitorsLocked(displayId, {}); + std::vector gestureMonitors = findTouchedGestureMonitorsLocked(displayId); for (TouchedMonitor& gestureMonitor : gestureMonitors) { sp connection = getConnectionLocked(gestureMonitor.monitor.inputChannel->getConnectionToken()); @@ -995,11 +994,9 @@ void InputDispatcher::addRecentEventLocked(std::shared_ptr entry) { sp InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y, TouchState* touchState, bool addOutsideTargets, - bool addPortalWindows, bool ignoreDragWindow) { - if ((addPortalWindows || addOutsideTargets) && touchState == nullptr) { - LOG_ALWAYS_FATAL( - "Must provide a valid touch state if adding portal windows or outside targets"); + if (addOutsideTargets && touchState == nullptr) { + LOG_ALWAYS_FATAL("Must provide a valid touch state if adding outside targets"); } // Traverse windows from front to back to find touched window. const std::vector>& windowHandles = getWindowHandlesLocked(displayId); @@ -1016,16 +1013,6 @@ sp InputDispatcher::findTouchedWindowAtLocked(int32_t display bool isTouchModal = !flags.test(InputWindowInfo::Flag::NOT_FOCUSABLE) && !flags.test(InputWindowInfo::Flag::NOT_TOUCH_MODAL); if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { - int32_t portalToDisplayId = windowInfo->portalToDisplayId; - if (portalToDisplayId != ADISPLAY_ID_NONE && - portalToDisplayId != displayId) { - if (addPortalWindows) { - // For the monitoring channels of the display. - touchState->addPortalWindow(windowHandle); - } - return findTouchedWindowAtLocked(portalToDisplayId, x, y, touchState, - addOutsideTargets, addPortalWindows); - } // Found window. return windowHandle; } @@ -1043,17 +1030,11 @@ sp InputDispatcher::findTouchedWindowAtLocked(int32_t display } std::vector InputDispatcher::findTouchedGestureMonitorsLocked( - int32_t displayId, const std::vector>& portalWindows) const { + int32_t displayId) const { std::vector touchedMonitors; std::vector monitors = getValueByKey(mGestureMonitorsByDisplay, displayId); addGestureMonitors(monitors, touchedMonitors); - for (const sp& portalWindow : portalWindows) { - const InputWindowInfo* windowInfo = portalWindow->getInfo(); - monitors = getValueByKey(mGestureMonitorsByDisplay, windowInfo->portalToDisplayId); - addGestureMonitors(monitors, touchedMonitors, -windowInfo->frameLeft, - -windowInfo->frameTop); - } return touchedMonitors; } @@ -1589,23 +1570,6 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr< // Add monitor channels from event's or focused display. addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry)); - if (isPointerEvent) { - std::unordered_map::iterator it = - mTouchStatesByDisplay.find(entry->displayId); - if (it != mTouchStatesByDisplay.end()) { - const TouchState& state = it->second; - if (!state.portalWindows.empty()) { - // The event has gone through these portal windows, so we add monitoring targets of - // the corresponding displays as well. - for (size_t i = 0; i < state.portalWindows.size(); i++) { - const InputWindowInfo* windowInfo = state.portalWindows[i]->getInfo(); - addGlobalMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId, - -windowInfo->frameLeft, -windowInfo->frameTop); - } - } - } - } - // Dispatch the motion. if (conflictingPointerActions) { CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, @@ -1993,12 +1957,11 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( y = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y)); } bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN; - newTouchedWindowHandle = - findTouchedWindowAtLocked(displayId, x, y, &tempTouchState, - isDown /*addOutsideTargets*/, true /*addPortalWindows*/); + newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState, + isDown /*addOutsideTargets*/); std::vector newGestureMonitors = isDown - ? findTouchedGestureMonitorsLocked(displayId, tempTouchState.portalWindows) + ? findTouchedGestureMonitorsLocked(displayId) : std::vector{}; // Figure out whether splitting will be allowed for this window. @@ -2369,8 +2332,7 @@ Failed: void InputDispatcher::finishDragAndDrop(int32_t displayId, float x, float y) { const sp dropWindow = findTouchedWindowAtLocked(displayId, x, y, nullptr /*touchState*/, - false /*addOutsideTargets*/, false /*addPortalWindows*/, - true /*ignoreDragWindow*/); + false /*addOutsideTargets*/, true /*ignoreDragWindow*/); if (dropWindow) { vec2 local = dropWindow->getInfo()->transform.transform(x, y); notifyDropWindowLocked(dropWindow->getToken(), local.x, local.y); @@ -2404,8 +2366,7 @@ void InputDispatcher::addDragEventLocked(const MotionEntry& entry) { const sp hoverWindowHandle = findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/, - false /*addOutsideTargets*/, false /*addPortalWindows*/, - true /*ignoreDragWindow*/); + false /*addOutsideTargets*/, true /*ignoreDragWindow*/); // enqueue drag exit if needed. if (hoverWindowHandle != mDragState->dragHoverWindowHandle && !haveSameToken(hoverWindowHandle, mDragState->dragHoverWindowHandle)) { @@ -4436,8 +4397,7 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked( } const InputWindowInfo* info = handle->getInfo(); - if ((getInputChannelLocked(handle->getToken()) == nullptr && - info->portalToDisplayId == ADISPLAY_ID_NONE)) { + if (getInputChannelLocked(handle->getToken()) == nullptr) { const bool noInputChannel = info->inputFeatures.test(InputWindowInfo::Feature::NO_INPUT_CHANNEL); const bool canReceiveInput = !info->flags.test(InputWindowInfo::Flag::NOT_TOUCHABLE) || @@ -4989,14 +4949,6 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { } else { dump += INDENT3 "Windows: \n"; } - if (!state.portalWindows.empty()) { - dump += INDENT3 "Portal windows:\n"; - for (size_t i = 0; i < state.portalWindows.size(); i++) { - const sp portalWindowHandle = state.portalWindows[i]; - dump += StringPrintf(INDENT4 "%zu: name='%s'\n", i, - portalWindowHandle->getName().c_str()); - } - } } } else { dump += INDENT "TouchStates: \n"; @@ -5018,7 +4970,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { const InputWindowInfo* windowInfo = windowHandle->getInfo(); dump += StringPrintf(INDENT3 "%zu: name='%s', id=%" PRId32 ", displayId=%d, " - "portalToDisplayId=%d, paused=%s, focusable=%s, " + "paused=%s, focusable=%s, " "hasWallpaper=%s, visible=%s, alpha=%.2f, " "flags=%s, type=%s, " "frame=[%d,%d][%d,%d], globalScale=%f, " @@ -5026,8 +4978,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { "applicationInfo.token=%s, " "touchableRegion=", i, windowInfo->name.c_str(), windowInfo->id, - windowInfo->displayId, windowInfo->portalToDisplayId, - toString(windowInfo->paused), + windowInfo->displayId, toString(windowInfo->paused), toString(windowInfo->focusable), toString(windowInfo->hasWallpaper), toString(windowInfo->visible), windowInfo->alpha, diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 9edf41c9c0..944e5b24be 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -211,7 +211,6 @@ private: sp findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y, TouchState* touchState, bool addOutsideTargets = false, - bool addPortalWindows = false, bool ignoreDragWindow = false) REQUIRES(mLock); sp getConnectionLocked(const sp& inputConnectionToken) const @@ -489,8 +488,7 @@ private: android::os::InputEventInjectionResult findTouchedWindowTargetsLocked( nsecs_t currentTime, const MotionEntry& entry, std::vector& inputTargets, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) REQUIRES(mLock); - std::vector findTouchedGestureMonitorsLocked( - int32_t displayId, const std::vector>& portalWindows) const + std::vector findTouchedGestureMonitorsLocked(int32_t displayId) const REQUIRES(mLock); std::vector selectResponsiveMonitorsLocked( const std::vector& gestureMonitors) const REQUIRES(mLock); diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index 81b3cf025b..3aabfc7e14 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -36,7 +36,6 @@ void TouchState::reset() { source = 0; displayId = ADISPLAY_ID_NONE; windows.clear(); - portalWindows.clear(); gestureMonitors.clear(); } @@ -47,7 +46,6 @@ void TouchState::copyFrom(const TouchState& other) { source = other.source; displayId = other.displayId; windows = other.windows; - portalWindows = other.portalWindows; gestureMonitors = other.gestureMonitors; } @@ -76,16 +74,6 @@ void TouchState::addOrUpdateWindow(const sp& windowHandle, in windows.push_back(touchedWindow); } -void TouchState::addPortalWindow(const sp& windowHandle) { - size_t numWindows = portalWindows.size(); - for (size_t i = 0; i < numWindows; i++) { - if (portalWindows[i] == windowHandle) { - return; - } - } - portalWindows.push_back(windowHandle); -} - void TouchState::addGestureMonitors(const std::vector& newMonitors) { const size_t newSize = gestureMonitors.size() + newMonitors.size(); gestureMonitors.reserve(newSize); @@ -118,7 +106,6 @@ void TouchState::filterNonAsIsTouchWindows() { void TouchState::filterNonMonitors() { windows.clear(); - portalWindows.clear(); } sp TouchState::getFirstForegroundWindowHandle() const { diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index 623c6a824f..f267e5532b 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -34,11 +34,6 @@ struct TouchState { int32_t displayId; // id to the display that currently has a touch, others are rejected std::vector windows; - // This collects the portal windows that the touch has gone through. Each portal window - // targets a display (embedded display for most cases). With this info, we can add the - // monitoring channels of the displays touched. - std::vector> portalWindows; - std::vector gestureMonitors; TouchState(); -- cgit v1.2.3-59-g8ed1b From 9b5fe58a3b75f3c9887ab2f7b2235729c39cd24b Mon Sep 17 00:00:00 2001 From: Tim Van Patten Date: Fri, 21 May 2021 17:51:59 -0600 Subject: Remove support: libfeature_support_angle.so Remove support for ANGLE's libfeature_support_angle.so. This also removes all of the logic related to checking the rules file, since libfeature_support_angle.so is what parsed the JSON rules file. Bug: 187342779 Test: make and manual verification ANGLE is loaded Change-Id: I3c52b07eb262f83f8e860584790ac058de58466a --- libs/graphicsenv/GraphicsEnv.cpp | 107 +-------------------- libs/graphicsenv/include/graphicsenv/GraphicsEnv.h | 7 +- 2 files changed, 4 insertions(+), 110 deletions(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index d54de4999c..7f0cac5d4f 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -343,80 +343,6 @@ void* GraphicsEnv::loadLibrary(std::string name) { return nullptr; } -bool GraphicsEnv::checkAngleRules(void* so) { - auto manufacturer = base::GetProperty("ro.product.manufacturer", "UNSET"); - auto model = base::GetProperty("ro.product.model", "UNSET"); - - auto ANGLEGetFeatureSupportUtilAPIVersion = - (fpANGLEGetFeatureSupportUtilAPIVersion)dlsym(so, - "ANGLEGetFeatureSupportUtilAPIVersion"); - - if (!ANGLEGetFeatureSupportUtilAPIVersion) { - ALOGW("Cannot find ANGLEGetFeatureSupportUtilAPIVersion function"); - return false; - } - - // Negotiate the interface version by requesting most recent known to the platform - unsigned int versionToUse = CURRENT_ANGLE_API_VERSION; - if (!(ANGLEGetFeatureSupportUtilAPIVersion)(&versionToUse)) { - ALOGW("Cannot use ANGLE feature-support library, it is older than supported by EGL, " - "requested version %u", - versionToUse); - return false; - } - - // Add and remove versions below as needed - bool useAngle = false; - switch (versionToUse) { - case 2: { - ALOGV("Using version %d of ANGLE feature-support library", versionToUse); - void* rulesHandle = nullptr; - int rulesVersion = 0; - void* systemInfoHandle = nullptr; - - // Get the symbols for the feature-support-utility library: -#define GET_SYMBOL(symbol) \ - fp##symbol symbol = (fp##symbol)dlsym(so, #symbol); \ - if (!symbol) { \ - ALOGW("Cannot find " #symbol " in ANGLE feature-support library"); \ - break; \ - } - GET_SYMBOL(ANGLEAndroidParseRulesString); - GET_SYMBOL(ANGLEGetSystemInfo); - GET_SYMBOL(ANGLEAddDeviceInfoToSystemInfo); - GET_SYMBOL(ANGLEShouldBeUsedForApplication); - GET_SYMBOL(ANGLEFreeRulesHandle); - GET_SYMBOL(ANGLEFreeSystemInfoHandle); - - // Parse the rules, obtain the SystemInfo, and evaluate the - // application against the rules: - if (!(ANGLEAndroidParseRulesString)(mRulesBuffer.data(), &rulesHandle, &rulesVersion)) { - ALOGW("ANGLE feature-support library cannot parse rules file"); - break; - } - if (!(ANGLEGetSystemInfo)(&systemInfoHandle)) { - ALOGW("ANGLE feature-support library cannot obtain SystemInfo"); - break; - } - if (!(ANGLEAddDeviceInfoToSystemInfo)(manufacturer.c_str(), model.c_str(), - systemInfoHandle)) { - ALOGW("ANGLE feature-support library cannot add device info to SystemInfo"); - break; - } - useAngle = (ANGLEShouldBeUsedForApplication)(rulesHandle, rulesVersion, - systemInfoHandle, mAngleAppName.c_str()); - (ANGLEFreeRulesHandle)(rulesHandle); - (ANGLEFreeSystemInfoHandle)(systemInfoHandle); - } break; - - default: - ALOGW("Version %u of ANGLE feature-support library is NOT supported.", versionToUse); - } - - ALOGV("Close temporarily-loaded ANGLE opt-in/out logic"); - return useAngle; -} - bool GraphicsEnv::shouldUseAngle(std::string appName) { if (appName != mAngleAppName) { // Make sure we are checking the app we were init'ed for @@ -444,31 +370,20 @@ void GraphicsEnv::updateUseAngle() { const char* ANGLE_PREFER_ANGLE = "angle"; const char* ANGLE_PREFER_NATIVE = "native"; + mUseAngle = NO; if (mAngleDeveloperOptIn == ANGLE_PREFER_ANGLE) { ALOGV("User set \"Developer Options\" to force the use of ANGLE"); mUseAngle = YES; } else if (mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) { ALOGV("User set \"Developer Options\" to force the use of Native"); - mUseAngle = NO; } else { - // The "Developer Options" value wasn't set to force the use of ANGLE. Need to temporarily - // load ANGLE and call the updatable opt-in/out logic: - void* featureSo = loadLibrary("feature_support"); - if (featureSo) { - ALOGV("loaded ANGLE's opt-in/out logic from namespace"); - mUseAngle = checkAngleRules(featureSo) ? YES : NO; - dlclose(featureSo); - featureSo = nullptr; - } else { - ALOGV("Could not load the ANGLE opt-in/out logic, cannot use ANGLE."); - } + ALOGV("User set invalid \"Developer Options\": '%s'", mAngleDeveloperOptIn.c_str()); } } void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName, const std::string developerOptIn, - const std::vector eglFeatures, const int rulesFd, - const long rulesOffset, const long rulesLength) { + const std::vector eglFeatures) { if (mUseAngle != UNKNOWN) { // We've already figured out an answer for this app, so just return. ALOGV("Already evaluated the rules file for '%s': use ANGLE = %s", appName.c_str(), @@ -485,22 +400,6 @@ void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName ALOGV("setting ANGLE application opt-in to '%s'", developerOptIn.c_str()); mAngleDeveloperOptIn = developerOptIn; - lseek(rulesFd, rulesOffset, SEEK_SET); - mRulesBuffer = std::vector(rulesLength + 1); - ssize_t numBytesRead = read(rulesFd, mRulesBuffer.data(), rulesLength); - if (numBytesRead < 0) { - ALOGE("Cannot read rules file: numBytesRead = %zd", numBytesRead); - numBytesRead = 0; - } else if (numBytesRead == 0) { - ALOGW("Empty rules file"); - } - if (numBytesRead != rulesLength) { - ALOGW("Did not read all of the necessary bytes from the rules file." - "expected: %ld, got: %zd", - rulesLength, numBytesRead); - } - mRulesBuffer[numBytesRead] = '\0'; - // Update the current status of whether we should use ANGLE or not updateUseAngle(); } diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index 900fc49b59..56d1139f57 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -97,8 +97,7 @@ public: // in the search path must have a '!' after the zip filename, e.g. // /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a void setAngleInfo(const std::string path, const std::string appName, std::string devOptIn, - const std::vector eglFeatures, const int rulesFd, - const long rulesOffset, const long rulesLength); + const std::vector eglFeatures); // Get the ANGLE driver namespace. android_namespace_t* getAngleNamespace(); // Get the app name for ANGLE debug message. @@ -129,8 +128,6 @@ private: // Load requested ANGLE library. void* loadLibrary(std::string name); - // Check ANGLE support with the rules. - bool checkAngleRules(void* so); // Update whether ANGLE should be used. void updateUseAngle(); // Link updatable driver namespace with llndk and vndk-sp libs. @@ -159,8 +156,6 @@ private: std::string mAngleDeveloperOptIn; // ANGLE EGL features; std::vector mAngleEglFeatures; - // ANGLE rules. - std::vector mRulesBuffer; // Use ANGLE flag. UseAngle mUseAngle = UNKNOWN; // Vulkan debug layers libs. -- cgit v1.2.3-59-g8ed1b From 98318de954ba00293cfd179266f09f266dc1c82b Mon Sep 17 00:00:00 2001 From: chaviw Date: Wed, 19 May 2021 16:45:23 -0500 Subject: Renamed and moved InputWindow and related files In preparation for the hierarchy listener interface, moved the InputWindow structs into libgui and have libinput dependant on libgui. Also renamed InputWindow to exclude Input since it will be used for more generic purposes. Test: Builds and flashes Bug: 188792659 Change-Id: I24262cbc14d409c00273de0024a672394a959e5f --- include/ftl/Flags.h | 280 ++++++++++++++++++++ include/ftl/NamedEnum.h | 125 +++++++++ include/input/DisplayViewport.h | 3 +- include/input/Flags.h | 283 --------------------- include/input/Input.h | 15 -- include/input/InputApplication.h | 85 ------- include/input/InputWindow.h | 279 -------------------- include/input/NamedEnum.h | 128 ---------- libs/ftl/Android.bp | 10 + libs/ftl/Flags_test.cpp | 227 +++++++++++++++++ libs/ftl/NamedEnum_test.cpp | 101 ++++++++ libs/gui/Android.bp | 56 +++- libs/gui/BLASTBufferQueue.cpp | 6 +- libs/gui/LayerState.cpp | 27 +- libs/gui/SurfaceComposerClient.cpp | 16 +- libs/gui/WindowInfo.cpp | 223 ++++++++++++++++ libs/gui/android/gui/FocusRequest.aidl | 45 ++++ libs/gui/android/gui/InputApplicationInfo.aidl | 23 ++ libs/gui/android/gui/TouchOcclusionMode.aidl | 47 ++++ libs/gui/android/gui/WindowInfo.aidl | 19 ++ libs/gui/include/gui/ISurfaceComposer.h | 2 +- libs/gui/include/gui/InputApplication.h | 79 ++++++ libs/gui/include/gui/LayerState.h | 14 +- libs/gui/include/gui/SurfaceComposerClient.h | 6 +- libs/gui/include/gui/WindowInfo.h | 273 ++++++++++++++++++++ libs/gui/include/gui/constants.h | 37 +++ libs/gui/tests/Android.bp | 1 + libs/gui/tests/EndToEndNativeInputTest.cpp | 27 +- libs/gui/tests/WindowInfo_test.cpp | 133 ++++++++++ libs/input/Android.bp | 14 +- libs/input/Input.cpp | 1 + libs/input/InputDevice.cpp | 2 +- libs/input/InputTransport.cpp | 2 +- libs/input/InputWindow.cpp | 224 ---------------- libs/input/KeyCharacterMap.cpp | 5 +- libs/input/KeyLayoutMap.cpp | 2 +- libs/input/android/FocusRequest.aidl | 45 ---- libs/input/android/InputApplicationInfo.aidl | 23 -- libs/input/android/InputWindowInfo.aidl | 20 -- libs/input/android/os/IInputFlinger.aidl | 6 +- libs/input/android/os/TouchOcclusionMode.aidl | 47 ---- libs/input/tests/Android.bp | 10 +- libs/input/tests/Flags_test.cpp | 227 ----------------- libs/input/tests/InputEvent_test.cpp | 24 +- .../input/tests/InputPublisherAndConsumer_test.cpp | 1 + libs/input/tests/InputWindow_test.cpp | 129 ---------- libs/input/tests/NamedEnum_test.cpp | 101 -------- libs/input/tests/VelocityTracker_test.cpp | 7 +- libs/input/tests/VerifiedInputEvent_test.cpp | 8 +- libs/nativedisplay/AChoreographer.cpp | 1 - services/inputflinger/InputManager.cpp | 16 +- services/inputflinger/InputManager.h | 4 +- services/inputflinger/InputReaderBase.cpp | 2 +- .../benchmarks/InputDispatcher_benchmarks.cpp | 11 +- services/inputflinger/dispatcher/DragState.cpp | 2 - services/inputflinger/dispatcher/DragState.h | 10 +- services/inputflinger/dispatcher/Entry.h | 2 +- services/inputflinger/dispatcher/FocusResolver.cpp | 15 +- services/inputflinger/dispatcher/FocusResolver.h | 18 +- .../inputflinger/dispatcher/InputDispatcher.cpp | 233 ++++++++--------- services/inputflinger/dispatcher/InputDispatcher.h | 90 ++++--- services/inputflinger/dispatcher/InputTarget.h | 3 +- services/inputflinger/dispatcher/TouchState.cpp | 11 +- services/inputflinger/dispatcher/TouchState.h | 12 +- services/inputflinger/dispatcher/TouchedWindow.h | 6 +- .../dispatcher/include/InputDispatcherInterface.h | 11 +- .../include/InputDispatcherPolicyInterface.h | 2 +- services/inputflinger/host/InputFlinger.h | 4 +- services/inputflinger/reader/InputDevice.cpp | 2 +- .../reader/controller/PeripheralController.cpp | 2 +- services/inputflinger/reader/include/EventHub.h | 2 +- services/inputflinger/reader/include/InputDevice.h | 2 +- .../reader/mapper/TouchInputMapper.cpp | 2 +- services/inputflinger/tests/Android.bp | 1 + services/inputflinger/tests/FocusResolver_test.cpp | 19 +- .../inputflinger/tests/IInputFlingerQuery.aidl | 6 +- .../tests/InputClassifierConverter_test.cpp | 2 +- .../inputflinger/tests/InputClassifier_test.cpp | 1 + .../inputflinger/tests/InputDispatcher_test.cpp | 149 +++++------ .../tests/InputFlingerService_test.cpp | 52 ++-- services/inputflinger/tests/InputReader_test.cpp | 1 + services/surfaceflinger/Android.bp | 1 - services/surfaceflinger/BufferLayer.cpp | 4 +- .../compositionengine/impl/planner/LayerState.h | 2 +- services/surfaceflinger/Layer.cpp | 24 +- services/surfaceflinger/Layer.h | 18 +- services/surfaceflinger/LayerProtoHelper.cpp | 7 +- services/surfaceflinger/LayerProtoHelper.h | 4 +- services/surfaceflinger/Scheduler/Scheduler.cpp | 9 +- services/surfaceflinger/SurfaceFlinger.cpp | 7 +- .../tests/RefreshRateOverlay_test.cpp | 4 + .../surfaceflinger/tests/utils/CallbackUtils.h | 4 + 92 files changed, 2158 insertions(+), 2088 deletions(-) create mode 100644 include/ftl/Flags.h create mode 100644 include/ftl/NamedEnum.h delete mode 100644 include/input/Flags.h delete mode 100644 include/input/InputApplication.h delete mode 100644 include/input/InputWindow.h delete mode 100644 include/input/NamedEnum.h create mode 100644 libs/ftl/Flags_test.cpp create mode 100644 libs/ftl/NamedEnum_test.cpp create mode 100644 libs/gui/WindowInfo.cpp create mode 100644 libs/gui/android/gui/FocusRequest.aidl create mode 100644 libs/gui/android/gui/InputApplicationInfo.aidl create mode 100644 libs/gui/android/gui/TouchOcclusionMode.aidl create mode 100644 libs/gui/android/gui/WindowInfo.aidl create mode 100644 libs/gui/include/gui/InputApplication.h create mode 100644 libs/gui/include/gui/WindowInfo.h create mode 100644 libs/gui/include/gui/constants.h create mode 100644 libs/gui/tests/WindowInfo_test.cpp delete mode 100644 libs/input/InputWindow.cpp delete mode 100644 libs/input/android/FocusRequest.aidl delete mode 100644 libs/input/android/InputApplicationInfo.aidl delete mode 100644 libs/input/android/InputWindowInfo.aidl delete mode 100644 libs/input/android/os/TouchOcclusionMode.aidl delete mode 100644 libs/input/tests/Flags_test.cpp delete mode 100644 libs/input/tests/InputWindow_test.cpp delete mode 100644 libs/input/tests/NamedEnum_test.cpp diff --git a/include/ftl/Flags.h b/include/ftl/Flags.h new file mode 100644 index 0000000000..27c84769cb --- /dev/null +++ b/include/ftl/Flags.h @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include "utils/BitSet.h" + +#pragma once + +namespace android { + +namespace details { + +template +inline constexpr auto flag_count = sizeof(F) * __CHAR_BIT__; + +template +constexpr auto generate_flag_values(std::integer_sequence seq) { + constexpr size_t count = seq.size(); + + std::array values{}; + for (size_t i = 0, v = 0; v < count; ++i) { + values[v++] = static_cast(T{1} << i); + } + + return values; +} + +template +inline constexpr auto flag_values = generate_flag_values( + std::make_integer_sequence, flag_count>{}); + +template +constexpr auto generate_flag_names(std::index_sequence) noexcept { + return std::array, sizeof...(I)>{ + {enum_value_name[I]>()...}}; +} + +template +inline constexpr auto flag_names = + generate_flag_names(std::make_index_sequence>{}); + +// A trait for determining whether a type is specifically an enum class or not. +template > +struct is_enum_class : std::false_type {}; + +// By definition, an enum class is an enum that is not implicitly convertible to its underlying +// type. +template +struct is_enum_class + : std::bool_constant>> {}; + +template +inline constexpr bool is_enum_class_v = is_enum_class::value; +} // namespace details + +template +constexpr auto flag_name() { + using F = decltype(V); + return details::enum_value_name(); +} + +template +constexpr std::optional flag_name(F flag) { + using U = std::underlying_type_t; + auto idx = static_cast(__builtin_ctzl(static_cast(flag))); + return details::flag_names[idx]; +} + +/* A class for handling flags defined by an enum or enum class in a type-safe way. */ +template +class Flags { + // F must be an enum or its underlying type is undefined. Theoretically we could specialize this + // further to avoid this restriction but in general we want to encourage the use of enums + // anyways. + static_assert(std::is_enum_v, "Flags type must be an enum"); + using U = typename std::underlying_type_t; + +public: + constexpr Flags(F f) : mFlags(static_cast(f)) {} + constexpr Flags() : mFlags(0) {} + constexpr Flags(const Flags& f) : mFlags(f.mFlags) {} + + // Provide a non-explicit construct for non-enum classes since they easily convert to their + // underlying types (e.g. when used with bitwise operators). For enum classes, however, we + // should force them to be explicitly constructed from their underlying types to make full use + // of the type checker. + template + constexpr Flags(T t, typename std::enable_if_t, T>* = nullptr) + : mFlags(t) {} + template + explicit constexpr Flags(T t, + typename std::enable_if_t, T>* = nullptr) + : mFlags(t) {} + + class Iterator { + // The type can't be larger than 64-bits otherwise it won't fit in BitSet64. + static_assert(sizeof(U) <= sizeof(uint64_t)); + + public: + Iterator(Flags flags) : mRemainingFlags(flags.mFlags) { (*this)++; } + Iterator() : mRemainingFlags(0), mCurrFlag(static_cast(0)) {} + + // Pre-fix ++ + Iterator& operator++() { + if (mRemainingFlags.isEmpty()) { + mCurrFlag = static_cast(0); + } else { + uint64_t bit = mRemainingFlags.clearLastMarkedBit(); // counts from left + const U flag = 1 << (64 - bit - 1); + mCurrFlag = static_cast(flag); + } + return *this; + } + + // Post-fix ++ + Iterator operator++(int) { + Iterator iter = *this; + ++*this; + return iter; + } + + bool operator==(Iterator other) const { + return mCurrFlag == other.mCurrFlag && mRemainingFlags == other.mRemainingFlags; + } + + bool operator!=(Iterator other) const { return !(*this == other); } + + F operator*() { return mCurrFlag; } + + // iterator traits + + // In the future we could make this a bidirectional const iterator instead of a forward + // iterator but it doesn't seem worth the added complexity at this point. This could not, + // however, be made a non-const iterator as assigning one flag to another is a non-sensical + // operation. + using iterator_category = std::input_iterator_tag; + using value_type = F; + // Per the C++ spec, because input iterators are not assignable the iterator's reference + // type does not actually need to be a reference. In fact, making it a reference would imply + // that modifying it would change the underlying Flags object, which is obviously wrong for + // the same reason this can't be a non-const iterator. + using reference = F; + using difference_type = void; + using pointer = void; + + private: + BitSet64 mRemainingFlags; + F mCurrFlag; + }; + + /* + * Tests whether the given flag is set. + */ + bool test(F flag) const { + U f = static_cast(flag); + return (f & mFlags) == f; + } + + /* Tests whether any of the given flags are set */ + bool any(Flags f) { return (mFlags & f.mFlags) != 0; } + + /* Tests whether all of the given flags are set */ + bool all(Flags f) { return (mFlags & f.mFlags) == f.mFlags; } + + Flags operator|(Flags rhs) const { return static_cast(mFlags | rhs.mFlags); } + Flags& operator|=(Flags rhs) { + mFlags = mFlags | rhs.mFlags; + return *this; + } + + Flags operator&(Flags rhs) const { return static_cast(mFlags & rhs.mFlags); } + Flags& operator&=(Flags rhs) { + mFlags = mFlags & rhs.mFlags; + return *this; + } + + Flags operator^(Flags rhs) const { return static_cast(mFlags ^ rhs.mFlags); } + Flags& operator^=(Flags rhs) { + mFlags = mFlags ^ rhs.mFlags; + return *this; + } + + Flags operator~() { return static_cast(~mFlags); } + + bool operator==(Flags rhs) const { return mFlags == rhs.mFlags; } + bool operator!=(Flags rhs) const { return !operator==(rhs); } + + Flags& operator=(const Flags& rhs) { + mFlags = rhs.mFlags; + return *this; + } + + Iterator begin() const { return Iterator(*this); } + + Iterator end() const { return Iterator(); } + + /* + * Returns the stored set of flags. + * + * Note that this returns the underlying type rather than the base enum class. This is because + * the value is no longer necessarily a strict member of the enum since the returned value could + * be multiple enum variants OR'd together. + */ + U get() const { return mFlags; } + + std::string string() const { + std::string result; + bool first = true; + U unstringified = 0; + for (const F f : *this) { + std::optional flagString = flag_name(f); + if (flagString) { + appendFlag(result, flagString.value(), first); + } else { + unstringified |= static_cast(f); + } + } + + if (unstringified != 0) { + appendFlag(result, base::StringPrintf("0x%08x", unstringified), first); + } + + if (first) { + result += "0x0"; + } + + return result; + } + +private: + U mFlags; + + static void appendFlag(std::string& str, const std::string_view& flag, bool& first) { + if (first) { + first = false; + } else { + str += " | "; + } + str += flag; + } +}; + +// This namespace provides operator overloads for enum classes to make it easier to work with them +// as flags. In order to use these, add them via a `using namespace` declaration. +namespace flag_operators { + +template >> +inline Flags operator~(F f) { + using U = typename std::underlying_type_t; + return static_cast(~static_cast(f)); +} +template >> +Flags operator|(F lhs, F rhs) { + using U = typename std::underlying_type_t; + return static_cast(static_cast(lhs) | static_cast(rhs)); +} + +} // namespace flag_operators +} // namespace android diff --git a/include/ftl/NamedEnum.h b/include/ftl/NamedEnum.h new file mode 100644 index 0000000000..f50ff46fe2 --- /dev/null +++ b/include/ftl/NamedEnum.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include + +#pragma once + +namespace android { + +namespace details { +template +constexpr std::optional enum_value_name() { + // Should look something like (but all on one line): + // std::optional + // android::details::enum_value_name() + // [E = android::test::TestEnums, V = android::test::TestEnums::ONE] + std::string_view view = __PRETTY_FUNCTION__; + size_t templateStart = view.rfind("["); + size_t templateEnd = view.rfind("]"); + if (templateStart == std::string::npos || templateEnd == std::string::npos) { + return std::nullopt; + } + + // Extract the template parameters without the enclosing braces. + // Example (cont'd): E = android::test::TestEnums, V = android::test::TestEnums::ONE + view = view.substr(templateStart + 1, templateEnd - templateStart - 1); + size_t valStart = view.rfind("V = "); + if (valStart == std::string::npos) { + return std::nullopt; + } + + // Example (cont'd): V = android::test::TestEnums::ONE + view = view.substr(valStart); + size_t nameStart = view.rfind("::"); + if (nameStart == std::string::npos) { + return std::nullopt; + } + + // Chop off the initial "::" + nameStart += 2; + return view.substr(nameStart); +} + +template +constexpr auto generate_enum_values(std::integer_sequence seq) { + constexpr size_t count = seq.size(); + + std::array values{}; + for (size_t i = 0, v = 0; v < count; ++i) { + values[v++] = static_cast(T{0} + i); + } + + return values; +} + +template +inline constexpr auto enum_values = + generate_enum_values(std::make_integer_sequence, N>{}); + +template +constexpr auto generate_enum_names(std::index_sequence) noexcept { + return std::array, sizeof...(I)>{ + {enum_value_name[I]>()...}}; +} + +template +inline constexpr auto enum_names = generate_enum_names(std::make_index_sequence{}); + +} // namespace details + +class NamedEnum { +public: + // By default allowed enum value range is 0 ~ 7. + template + static constexpr size_t max = 8; + + template + static constexpr auto enum_name() { + using E = decltype(V); + return details::enum_value_name(); + } + + template + static constexpr std::optional enum_name(E val) { + auto idx = static_cast(val); + return idx < max ? details::enum_names>[idx] : std::nullopt; + } + + // Helper function for parsing enum value to string. + // Example : enum class TestEnums { ZERO = 0x0 }; + // NamedEnum::string(TestEnums::ZERO) returns string of "ZERO". + // Note the default maximum enum is 8, if the enum ID to be parsed if greater than 8 like 16, + // it should be declared to specialized the maximum enum by below: + // template <> constexpr size_t NamedEnum::max = 16; + // If the enum class definition is sparse and contains enum values starting from a large value, + // Do not specialize it to a large number to avoid performance issues. + // The recommended maximum enum number to specialize is 64. + template + static const std::string string(E val, const char* fallbackFormat = "%02d") { + std::string result; + std::optional enumString = enum_name(val); + result += enumString ? enumString.value() : base::StringPrintf(fallbackFormat, val); + return result; + } +}; + +} // namespace android diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h index 5e40ca7ece..a6213f3ddd 100644 --- a/include/input/DisplayViewport.h +++ b/include/input/DisplayViewport.h @@ -18,8 +18,9 @@ #define _LIBINPUT_DISPLAY_VIEWPORT_H #include +#include +#include #include -#include #include #include diff --git a/include/input/Flags.h b/include/input/Flags.h deleted file mode 100644 index b12a9ed2c5..0000000000 --- a/include/input/Flags.h +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include -#include -#include -#include -#include - -#include "NamedEnum.h" -#include "utils/BitSet.h" - -#ifndef __UI_INPUT_FLAGS_H -#define __UI_INPUT_FLAGS_H - -namespace android { - -namespace details { - -template -inline constexpr auto flag_count = sizeof(F) * __CHAR_BIT__; - -template -constexpr auto generate_flag_values(std::integer_sequence seq) { - constexpr size_t count = seq.size(); - - std::array values{}; - for (size_t i = 0, v = 0; v < count; ++i) { - values[v++] = static_cast(T{1} << i); - } - - return values; -} - -template -inline constexpr auto flag_values = generate_flag_values( - std::make_integer_sequence, flag_count>{}); - -template -constexpr auto generate_flag_names(std::index_sequence) noexcept { - return std::array, sizeof...(I)>{ - {enum_value_name[I]>()...}}; -} - -template -inline constexpr auto flag_names = - generate_flag_names(std::make_index_sequence>{}); - -// A trait for determining whether a type is specifically an enum class or not. -template > -struct is_enum_class : std::false_type {}; - -// By definition, an enum class is an enum that is not implicitly convertible to its underlying -// type. -template -struct is_enum_class - : std::bool_constant>> {}; - -template -inline constexpr bool is_enum_class_v = is_enum_class::value; -} // namespace details - -template -constexpr auto flag_name() { - using F = decltype(V); - return details::enum_value_name(); -} - -template -constexpr std::optional flag_name(F flag) { - using U = std::underlying_type_t; - auto idx = static_cast(__builtin_ctzl(static_cast(flag))); - return details::flag_names[idx]; -} - -/* A class for handling flags defined by an enum or enum class in a type-safe way. */ -template -class Flags { - // F must be an enum or its underlying type is undefined. Theoretically we could specialize this - // further to avoid this restriction but in general we want to encourage the use of enums - // anyways. - static_assert(std::is_enum_v, "Flags type must be an enum"); - using U = typename std::underlying_type_t; - -public: - constexpr Flags(F f) : mFlags(static_cast(f)) {} - constexpr Flags() : mFlags(0) {} - constexpr Flags(const Flags& f) : mFlags(f.mFlags) {} - - // Provide a non-explicit construct for non-enum classes since they easily convert to their - // underlying types (e.g. when used with bitwise operators). For enum classes, however, we - // should force them to be explicitly constructed from their underlying types to make full use - // of the type checker. - template - constexpr Flags(T t, typename std::enable_if_t, T>* = nullptr) - : mFlags(t) {} - template - explicit constexpr Flags(T t, - typename std::enable_if_t, T>* = nullptr) - : mFlags(t) {} - - class Iterator { - // The type can't be larger than 64-bits otherwise it won't fit in BitSet64. - static_assert(sizeof(U) <= sizeof(uint64_t)); - - public: - Iterator(Flags flags) : mRemainingFlags(flags.mFlags) { (*this)++; } - Iterator() : mRemainingFlags(0), mCurrFlag(static_cast(0)) {} - - // Pre-fix ++ - Iterator& operator++() { - if (mRemainingFlags.isEmpty()) { - mCurrFlag = static_cast(0); - } else { - uint64_t bit = mRemainingFlags.clearLastMarkedBit(); // counts from left - const U flag = 1 << (64 - bit - 1); - mCurrFlag = static_cast(flag); - } - return *this; - } - - // Post-fix ++ - Iterator operator++(int) { - Iterator iter = *this; - ++*this; - return iter; - } - - bool operator==(Iterator other) const { - return mCurrFlag == other.mCurrFlag && mRemainingFlags == other.mRemainingFlags; - } - - bool operator!=(Iterator other) const { return !(*this == other); } - - F operator*() { return mCurrFlag; } - - // iterator traits - - // In the future we could make this a bidirectional const iterator instead of a forward - // iterator but it doesn't seem worth the added complexity at this point. This could not, - // however, be made a non-const iterator as assigning one flag to another is a non-sensical - // operation. - using iterator_category = std::input_iterator_tag; - using value_type = F; - // Per the C++ spec, because input iterators are not assignable the iterator's reference - // type does not actually need to be a reference. In fact, making it a reference would imply - // that modifying it would change the underlying Flags object, which is obviously wrong for - // the same reason this can't be a non-const iterator. - using reference = F; - using difference_type = void; - using pointer = void; - - private: - BitSet64 mRemainingFlags; - F mCurrFlag; - }; - - /* - * Tests whether the given flag is set. - */ - bool test(F flag) const { - U f = static_cast(flag); - return (f & mFlags) == f; - } - - /* Tests whether any of the given flags are set */ - bool any(Flags f) { return (mFlags & f.mFlags) != 0; } - - /* Tests whether all of the given flags are set */ - bool all(Flags f) { return (mFlags & f.mFlags) == f.mFlags; } - - Flags operator|(Flags rhs) const { return static_cast(mFlags | rhs.mFlags); } - Flags& operator|=(Flags rhs) { - mFlags = mFlags | rhs.mFlags; - return *this; - } - - Flags operator&(Flags rhs) const { return static_cast(mFlags & rhs.mFlags); } - Flags& operator&=(Flags rhs) { - mFlags = mFlags & rhs.mFlags; - return *this; - } - - Flags operator^(Flags rhs) const { return static_cast(mFlags ^ rhs.mFlags); } - Flags& operator^=(Flags rhs) { - mFlags = mFlags ^ rhs.mFlags; - return *this; - } - - Flags operator~() { return static_cast(~mFlags); } - - bool operator==(Flags rhs) const { return mFlags == rhs.mFlags; } - bool operator!=(Flags rhs) const { return !operator==(rhs); } - - Flags& operator=(const Flags& rhs) { - mFlags = rhs.mFlags; - return *this; - } - - Iterator begin() const { return Iterator(*this); } - - Iterator end() const { return Iterator(); } - - /* - * Returns the stored set of flags. - * - * Note that this returns the underlying type rather than the base enum class. This is because - * the value is no longer necessarily a strict member of the enum since the returned value could - * be multiple enum variants OR'd together. - */ - U get() const { return mFlags; } - - std::string string() const { - std::string result; - bool first = true; - U unstringified = 0; - for (const F f : *this) { - std::optional flagString = flag_name(f); - if (flagString) { - appendFlag(result, flagString.value(), first); - } else { - unstringified |= static_cast(f); - } - } - - if (unstringified != 0) { - appendFlag(result, base::StringPrintf("0x%08x", unstringified), first); - } - - if (first) { - result += "0x0"; - } - - return result; - } - -private: - U mFlags; - - static void appendFlag(std::string& str, const std::string_view& flag, bool& first) { - if (first) { - first = false; - } else { - str += " | "; - } - str += flag; - } -}; - -// This namespace provides operator overloads for enum classes to make it easier to work with them -// as flags. In order to use these, add them via a `using namespace` declaration. -namespace flag_operators { - -template >> -inline Flags operator~(F f) { - using U = typename std::underlying_type_t; - return static_cast(~static_cast(f)); -} -template >> -Flags operator|(F lhs, F rhs) { - using U = typename std::underlying_type_t; - return static_cast(static_cast(lhs) | static_cast(rhs)); -} - -} // namespace flag_operators -} // namespace android - -#endif // __UI_INPUT_FLAGS_H diff --git a/include/input/Input.h b/include/input/Input.h index 438121b30e..3bac7636e7 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -105,15 +105,6 @@ constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS = */ constexpr int32_t AMOTION_EVENT_FLAG_CANCELED = 0x20; -enum { - /* Used when a motion event is not associated with any display. - * Typically used for non-pointer events. */ - ADISPLAY_ID_NONE = -1, - - /* The default display id. */ - ADISPLAY_ID_DEFAULT = 0, -}; - enum { /* * Indicates that an input device has switches. @@ -338,12 +329,6 @@ private: */ constexpr float AMOTION_EVENT_INVALID_CURSOR_POSITION = std::numeric_limits::quiet_NaN(); -/** - * Invalid value for display size. Used when display size isn't available for an event or doesn't - * matter. This is just a constant 0 so that it has no effect if unused. - */ -constexpr int32_t AMOTION_EVENT_INVALID_DISPLAY_SIZE = 0; - /* * Pointer coordinate data. */ diff --git a/include/input/InputApplication.h b/include/input/InputApplication.h deleted file mode 100644 index 8e4fe796a5..0000000000 --- a/include/input/InputApplication.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2011 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. - */ - -#ifndef _UI_INPUT_APPLICATION_H -#define _UI_INPUT_APPLICATION_H - -#include - -#include - -#include -#include -#include - -#include -#include -#include - -namespace android { -/* - * Handle for an application that can receive input. - * - * Used by the native input dispatcher as a handle for the window manager objects - * that describe an application. - */ -class InputApplicationHandle { -public: - inline const InputApplicationInfo* getInfo() const { - return &mInfo; - } - - inline std::string getName() const { - return !mInfo.name.empty() ? mInfo.name : ""; - } - - inline std::chrono::nanoseconds getDispatchingTimeout( - std::chrono::nanoseconds defaultValue) const { - return mInfo.token ? std::chrono::milliseconds(mInfo.dispatchingTimeoutMillis) - : defaultValue; - } - - inline sp getApplicationToken() const { - return mInfo.token; - } - - bool operator==(const InputApplicationHandle& other) const { - return getName() == other.getName() && getApplicationToken() == other.getApplicationToken(); - } - - bool operator!=(const InputApplicationHandle& other) const { return !(*this == other); } - - /** - * Requests that the state of this object be updated to reflect - * the most current available information about the application. - * - * This method should only be called from within the input dispatcher's - * critical section. - * - * Returns true on success, or false if the handle is no longer valid. - */ - virtual bool updateInfo() = 0; - -protected: - InputApplicationHandle() = default; - virtual ~InputApplicationHandle() = default; - - InputApplicationInfo mInfo; -}; - -} // namespace android - -#endif // _UI_INPUT_APPLICATION_H diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h deleted file mode 100644 index 121be6d963..0000000000 --- a/include/input/InputWindow.h +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright (C) 2011 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. - */ - -#ifndef _UI_INPUT_WINDOW_H -#define _UI_INPUT_WINDOW_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "InputApplication.h" - -using android::os::TouchOcclusionMode; - -namespace android { - -/* - * Describes the properties of a window that can receive input. - */ -struct InputWindowInfo : public Parcelable { - InputWindowInfo() = default; - - // Window flags from WindowManager.LayoutParams - enum class Flag : uint32_t { - ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, - DIM_BEHIND = 0x00000002, - BLUR_BEHIND = 0x00000004, - NOT_FOCUSABLE = 0x00000008, - NOT_TOUCHABLE = 0x00000010, - NOT_TOUCH_MODAL = 0x00000020, - TOUCHABLE_WHEN_WAKING = 0x00000040, - KEEP_SCREEN_ON = 0x00000080, - LAYOUT_IN_SCREEN = 0x00000100, - LAYOUT_NO_LIMITS = 0x00000200, - FULLSCREEN = 0x00000400, - FORCE_NOT_FULLSCREEN = 0x00000800, - DITHER = 0x00001000, - SECURE = 0x00002000, - SCALED = 0x00004000, - IGNORE_CHEEK_PRESSES = 0x00008000, - LAYOUT_INSET_DECOR = 0x00010000, - ALT_FOCUSABLE_IM = 0x00020000, - WATCH_OUTSIDE_TOUCH = 0x00040000, - SHOW_WHEN_LOCKED = 0x00080000, - SHOW_WALLPAPER = 0x00100000, - TURN_SCREEN_ON = 0x00200000, - DISMISS_KEYGUARD = 0x00400000, - SPLIT_TOUCH = 0x00800000, - HARDWARE_ACCELERATED = 0x01000000, - LAYOUT_IN_OVERSCAN = 0x02000000, - TRANSLUCENT_STATUS = 0x04000000, - TRANSLUCENT_NAVIGATION = 0x08000000, - LOCAL_FOCUS_MODE = 0x10000000, - SLIPPERY = 0x20000000, - LAYOUT_ATTACHED_IN_DECOR = 0x40000000, - DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000, - }; // Window types from WindowManager.LayoutParams - - enum class Type : int32_t { - UNKNOWN = 0, - FIRST_APPLICATION_WINDOW = 1, - BASE_APPLICATION = 1, - APPLICATION = 2, - APPLICATION_STARTING = 3, - LAST_APPLICATION_WINDOW = 99, - FIRST_SUB_WINDOW = 1000, - APPLICATION_PANEL = FIRST_SUB_WINDOW, - APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1, - APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2, - APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3, - APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4, - LAST_SUB_WINDOW = 1999, - FIRST_SYSTEM_WINDOW = 2000, - STATUS_BAR = FIRST_SYSTEM_WINDOW, - SEARCH_BAR = FIRST_SYSTEM_WINDOW + 1, - PHONE = FIRST_SYSTEM_WINDOW + 2, - SYSTEM_ALERT = FIRST_SYSTEM_WINDOW + 3, - KEYGUARD = FIRST_SYSTEM_WINDOW + 4, - TOAST = FIRST_SYSTEM_WINDOW + 5, - SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 6, - PRIORITY_PHONE = FIRST_SYSTEM_WINDOW + 7, - SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW + 8, - KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW + 9, - SYSTEM_ERROR = FIRST_SYSTEM_WINDOW + 10, - INPUT_METHOD = FIRST_SYSTEM_WINDOW + 11, - INPUT_METHOD_DIALOG = FIRST_SYSTEM_WINDOW + 12, - WALLPAPER = FIRST_SYSTEM_WINDOW + 13, - STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW + 14, - SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 15, - DRAG = FIRST_SYSTEM_WINDOW + 16, - STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW + 17, - POINTER = FIRST_SYSTEM_WINDOW + 18, - NAVIGATION_BAR = FIRST_SYSTEM_WINDOW + 19, - VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW + 20, - BOOT_PROGRESS = FIRST_SYSTEM_WINDOW + 21, - INPUT_CONSUMER = FIRST_SYSTEM_WINDOW + 22, - NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW + 24, - MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 27, - ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW + 32, - DOCK_DIVIDER = FIRST_SYSTEM_WINDOW + 34, - ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 39, - NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40, - LAST_SYSTEM_WINDOW = 2999, - }; - - enum class Feature { - DISABLE_TOUCH_PAD_GESTURES = 0x00000001, - NO_INPUT_CHANNEL = 0x00000002, - DISABLE_USER_ACTIVITY = 0x00000004, - }; - - /* These values are filled in by the WM and passed through SurfaceFlinger - * unless specified otherwise. - */ - // This value should NOT be used to uniquely identify the window. There may be different - // input windows that have the same token. - sp token; - // This uniquely identifies the input window. - int32_t id = -1; - std::string name; - Flags flags; - Type type = Type::UNKNOWN; - std::chrono::nanoseconds dispatchingTimeout = std::chrono::seconds(5); - - /* These values are filled in by SurfaceFlinger. */ - int32_t frameLeft = -1; - int32_t frameTop = -1; - int32_t frameRight = -1; - int32_t frameBottom = -1; - - /* - * SurfaceFlinger consumes this value to shrink the computed frame. This is - * different from shrinking the touchable region in that it DOES shift the coordinate - * space where-as the touchable region does not and is more like "cropping". This - * is used for window shadows. - */ - int32_t surfaceInset = 0; - - // A global scaling factor for all windows. Unlike windowScaleX/Y this results - // in scaling of the TOUCH_MAJOR/TOUCH_MINOR axis. - float globalScaleFactor = 1.0f; - - // The opacity of this window, from 0.0 to 1.0 (inclusive). - // An alpha of 1.0 means fully opaque and 0.0 means fully transparent. - float alpha; - - // Transform applied to individual windows. - ui::Transform transform; - - // Display size in its natural rotation. Used to rotate raw coordinates for compatibility. - int32_t displayWidth = AMOTION_EVENT_INVALID_DISPLAY_SIZE; - int32_t displayHeight = AMOTION_EVENT_INVALID_DISPLAY_SIZE; - - /* - * This is filled in by the WM relative to the frame and then translated - * to absolute coordinates by SurfaceFlinger once the frame is computed. - */ - Region touchableRegion; - bool visible = false; - bool focusable = false; - bool hasWallpaper = false; - bool paused = false; - /* This flag is set when the window is of a trusted type that is allowed to silently - * overlay other windows for the purpose of implementing the secure views feature. - * Trusted overlays, such as IME windows, can partly obscure other windows without causing - * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. - */ - bool trustedOverlay = false; - TouchOcclusionMode touchOcclusionMode = TouchOcclusionMode::BLOCK_UNTRUSTED; - int32_t ownerPid = -1; - int32_t ownerUid = -1; - std::string packageName; - Flags inputFeatures; - int32_t displayId = ADISPLAY_ID_NONE; - int32_t portalToDisplayId = ADISPLAY_ID_NONE; - InputApplicationInfo applicationInfo; - bool replaceTouchableRegionWithCrop = false; - wp touchableRegionCropHandle; - - void addTouchableRegion(const Rect& region); - - bool touchableRegionContainsPoint(int32_t x, int32_t y) const; - - bool frameContainsPoint(int32_t x, int32_t y) const; - - bool supportsSplitTouch() const; - - bool overlaps(const InputWindowInfo* other) const; - - bool operator==(const InputWindowInfo& inputChannel) const; - - status_t writeToParcel(android::Parcel* parcel) const override; - - status_t readFromParcel(const android::Parcel* parcel) override; -}; - -/* - * Handle for a window that can receive input. - * - * Used by the native input dispatcher to indirectly refer to the window manager objects - * that describe a window. - */ -class InputWindowHandle : public RefBase { -public: - explicit InputWindowHandle(); - InputWindowHandle(const InputWindowHandle& other); - InputWindowHandle(const InputWindowInfo& other); - - inline const InputWindowInfo* getInfo() const { return &mInfo; } - - sp getToken() const; - - int32_t getId() const { return mInfo.id; } - - sp getApplicationToken() { return mInfo.applicationInfo.token; } - - inline std::string getName() const { return !mInfo.name.empty() ? mInfo.name : ""; } - - inline std::chrono::nanoseconds getDispatchingTimeout( - std::chrono::nanoseconds defaultValue) const { - return mInfo.token ? std::chrono::nanoseconds(mInfo.dispatchingTimeout) : defaultValue; - } - - /** - * Requests that the state of this object be updated to reflect - * the most current available information about the application. - * As this class is created as RefBase object, no pure virtual function is allowed. - * - * This method should only be called from within the input dispatcher's - * critical section. - * - * Returns true on success, or false if the handle is no longer valid. - */ - virtual bool updateInfo() { return false; } - - /** - * Updates from another input window handle. - */ - void updateFrom(const sp handle); - - /** - * Releases the channel used by the associated information when it is - * no longer needed. - */ - void releaseChannel(); - - // Not override since this class is not derrived from Parcelable. - status_t readFromParcel(const android::Parcel* parcel); - status_t writeToParcel(android::Parcel* parcel) const; - -protected: - virtual ~InputWindowHandle(); - - InputWindowInfo mInfo; -}; -} // namespace android - -#endif // _UI_INPUT_WINDOW_H diff --git a/include/input/NamedEnum.h b/include/input/NamedEnum.h deleted file mode 100644 index 6562348701..0000000000 --- a/include/input/NamedEnum.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include -#include -#include -#include - -#ifndef __UI_INPUT_NAMEDENUM_H -#define __UI_INPUT_NAMEDENUM_H - -namespace android { - -namespace details { -template -constexpr std::optional enum_value_name() { - // Should look something like (but all on one line): - // std::optional - // android::details::enum_value_name() - // [E = android::test::TestEnums, V = android::test::TestEnums::ONE] - std::string_view view = __PRETTY_FUNCTION__; - size_t templateStart = view.rfind("["); - size_t templateEnd = view.rfind("]"); - if (templateStart == std::string::npos || templateEnd == std::string::npos) { - return std::nullopt; - } - - // Extract the template parameters without the enclosing braces. - // Example (cont'd): E = android::test::TestEnums, V = android::test::TestEnums::ONE - view = view.substr(templateStart + 1, templateEnd - templateStart - 1); - size_t valStart = view.rfind("V = "); - if (valStart == std::string::npos) { - return std::nullopt; - } - - // Example (cont'd): V = android::test::TestEnums::ONE - view = view.substr(valStart); - size_t nameStart = view.rfind("::"); - if (nameStart == std::string::npos) { - return std::nullopt; - } - - // Chop off the initial "::" - nameStart += 2; - return view.substr(nameStart); -} - -template -constexpr auto generate_enum_values(std::integer_sequence seq) { - constexpr size_t count = seq.size(); - - std::array values{}; - for (size_t i = 0, v = 0; v < count; ++i) { - values[v++] = static_cast(T{0} + i); - } - - return values; -} - -template -inline constexpr auto enum_values = - generate_enum_values(std::make_integer_sequence, N>{}); - -template -constexpr auto generate_enum_names(std::index_sequence) noexcept { - return std::array, sizeof...(I)>{ - {enum_value_name[I]>()...}}; -} - -template -inline constexpr auto enum_names = generate_enum_names(std::make_index_sequence{}); - -} // namespace details - -class NamedEnum { -public: - // By default allowed enum value range is 0 ~ 7. - template - static constexpr size_t max = 8; - - template - static constexpr auto enum_name() { - using E = decltype(V); - return details::enum_value_name(); - } - - template - static constexpr std::optional enum_name(E val) { - auto idx = static_cast(val); - return idx < max ? details::enum_names>[idx] : std::nullopt; - } - - // Helper function for parsing enum value to string. - // Example : enum class TestEnums { ZERO = 0x0 }; - // NamedEnum::string(TestEnums::ZERO) returns string of "ZERO". - // Note the default maximum enum is 8, if the enum ID to be parsed if greater than 8 like 16, - // it should be declared to specialized the maximum enum by below: - // template <> constexpr size_t NamedEnum::max = 16; - // If the enum class definition is sparse and contains enum values starting from a large value, - // Do not specialize it to a large number to avoid performance issues. - // The recommended maximum enum number to specialize is 64. - template - static const std::string string(E val, const char* fallbackFormat = "%02d") { - std::string result; - std::optional enumString = enum_name(val); - result += enumString ? enumString.value() : base::StringPrintf(fallbackFormat, val); - return result; - } -}; - -} // namespace android - -#endif // __UI_INPUT_NAMEDENUM_H \ No newline at end of file diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 436620350a..3026921044 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -15,7 +15,9 @@ cc_test { }, srcs: [ "cast_test.cpp", + "Flags_test.cpp", "future_test.cpp", + "NamedEnum_test.cpp", "small_map_test.cpp", "small_vector_test.cpp", "static_vector_test.cpp", @@ -27,4 +29,12 @@ cc_test { "-Wextra", "-Wpedantic", ], + + header_libs: [ + "libbase_headers", + ], + + shared_libs: [ + "libbase", + ], } diff --git a/libs/ftl/Flags_test.cpp b/libs/ftl/Flags_test.cpp new file mode 100644 index 0000000000..8c00b5299b --- /dev/null +++ b/libs/ftl/Flags_test.cpp @@ -0,0 +1,227 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +namespace android::test { + +using namespace android::flag_operators; + +enum class TestFlags { ONE = 0x1, TWO = 0x2, THREE = 0x4 }; + +TEST(Flags, Test) { + Flags flags = TestFlags::ONE; + ASSERT_TRUE(flags.test(TestFlags::ONE)); + ASSERT_FALSE(flags.test(TestFlags::TWO)); + ASSERT_FALSE(flags.test(TestFlags::THREE)); +} + +TEST(Flags, Any) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + ASSERT_TRUE(flags.any(TestFlags::ONE)); + ASSERT_TRUE(flags.any(TestFlags::TWO)); + ASSERT_FALSE(flags.any(TestFlags::THREE)); + ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::TWO)); + ASSERT_TRUE(flags.any(TestFlags::TWO | TestFlags::THREE)); + ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::THREE)); + ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, All) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + ASSERT_TRUE(flags.all(TestFlags::ONE)); + ASSERT_TRUE(flags.all(TestFlags::TWO)); + ASSERT_FALSE(flags.all(TestFlags::THREE)); + ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::TWO)); + ASSERT_FALSE(flags.all(TestFlags::TWO | TestFlags::THREE)); + ASSERT_FALSE(flags.all(TestFlags::ONE | TestFlags::THREE)); + ASSERT_FALSE(flags.all(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, DefaultConstructor_hasNoFlagsSet) { + Flags flags; + ASSERT_FALSE(flags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, NotOperator_onEmptyFlagsSetsAllFlags) { + Flags flags; + flags = ~flags; + ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, NotOperator_onNonEmptyFlagsInvertsFlags) { + Flags flags = TestFlags::TWO; + flags = ~flags; + ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::THREE)); + ASSERT_FALSE(flags.test(TestFlags::TWO)); +} + +TEST(Flags, OrOperator_withNewFlag) { + Flags flags = TestFlags::ONE; + Flags flags2 = flags | TestFlags::TWO; + ASSERT_FALSE(flags2.test(TestFlags::THREE)); + ASSERT_TRUE(flags2.all(TestFlags::ONE | TestFlags::TWO)); +} + +TEST(Flags, OrOperator_withExistingFlag) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + Flags flags2 = flags | TestFlags::THREE; + ASSERT_FALSE(flags2.test(TestFlags::TWO)); + ASSERT_TRUE(flags2.all(TestFlags::ONE | TestFlags::THREE)); +} + +TEST(Flags, OrEqualsOperator_withNewFlag) { + Flags flags; + flags |= TestFlags::THREE; + ASSERT_TRUE(flags.test(TestFlags::THREE)); + ASSERT_FALSE(flags.any(TestFlags::ONE | TestFlags::TWO)); +} + +TEST(Flags, OrEqualsOperator_withExistingFlag) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + flags |= TestFlags::THREE; + ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::THREE)); + ASSERT_FALSE(flags.test(TestFlags::TWO)); +} + +TEST(Flags, AndOperator_withOneSetFlag) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + Flags andFlags = flags & TestFlags::THREE; + ASSERT_TRUE(andFlags.test(TestFlags::THREE)); + ASSERT_FALSE(andFlags.any(TestFlags::ONE | TestFlags::TWO)); +} + +TEST(Flags, AndOperator_withMultipleSetFlags) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + Flags andFlags = flags & (TestFlags::ONE | TestFlags::THREE); + ASSERT_TRUE(andFlags.all(TestFlags::ONE | TestFlags::THREE)); + ASSERT_FALSE(andFlags.test(TestFlags::TWO)); +} + +TEST(Flags, AndOperator_withNoSetFlags) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + Flags andFlags = flags & TestFlags::TWO; + ASSERT_FALSE(andFlags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, Equality) { + Flags flags1 = TestFlags::ONE | TestFlags::TWO; + Flags flags2 = TestFlags::ONE | TestFlags::TWO; + ASSERT_EQ(flags1, flags2); +} + +TEST(Flags, Inequality) { + Flags flags1 = TestFlags::ONE | TestFlags::TWO; + Flags flags2 = TestFlags::ONE | TestFlags::THREE; + ASSERT_NE(flags1, flags2); +} + +TEST(Flags, EqualsOperator) { + Flags flags; + flags = TestFlags::ONE; + ASSERT_TRUE(flags.test(TestFlags::ONE)); + ASSERT_FALSE(flags.any(TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, EqualsOperator_DontShareState) { + Flags flags1 = TestFlags::ONE | TestFlags::TWO; + Flags flags2 = flags1; + ASSERT_EQ(flags1, flags2); + + flags1 &= TestFlags::TWO; + ASSERT_NE(flags1, flags2); +} + +TEST(Flags, GetValue) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + ASSERT_EQ(flags.get(), 0x3); +} + +TEST(Flags, String_NoFlags) { + Flags flags; + ASSERT_EQ(flags.string(), "0x0"); +} + +TEST(Flags, String_KnownValues) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + ASSERT_EQ(flags.string(), "ONE | TWO"); +} + +TEST(Flags, String_UnknownValues) { + auto flags = Flags(0b1011); + ASSERT_EQ(flags.string(), "ONE | TWO | 0x00000008"); +} + +TEST(FlagsIterator, IteratesOverAllFlags) { + Flags flags1 = TestFlags::ONE | TestFlags::TWO; + Flags flags2; + for (TestFlags f : flags1) { + flags2 |= f; + } + ASSERT_EQ(flags2, flags1); +} + +TEST(FlagsIterator, IteratesInExpectedOrder) { + const std::vector flagOrder = {TestFlags::ONE, TestFlags::TWO}; + Flags flags; + for (TestFlags f : flagOrder) { + flags |= f; + } + + size_t idx = 0; + auto iter = flags.begin(); + while (iter != flags.end() && idx < flagOrder.size()) { + // Make sure the order is what we expect + ASSERT_EQ(*iter, flagOrder[idx]); + iter++; + idx++; + } + ASSERT_EQ(iter, flags.end()); +} +TEST(FlagsIterator, PostFixIncrement) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + auto iter = flags.begin(); + ASSERT_EQ(*(iter++), TestFlags::ONE); + ASSERT_EQ(*iter, TestFlags::TWO); + ASSERT_EQ(*(iter++), TestFlags::TWO); + ASSERT_EQ(iter, flags.end()); +} + +TEST(FlagsIterator, PreFixIncrement) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + auto iter = flags.begin(); + ASSERT_EQ(*++iter, TestFlags::TWO); + ASSERT_EQ(++iter, flags.end()); +} + +TEST(FlagNames, RuntimeFlagName) { + TestFlags f = TestFlags::ONE; + ASSERT_EQ(flag_name(f), "ONE"); +} + +TEST(FlagNames, RuntimeUnknownFlagName) { + TestFlags f = static_cast(0x8); + ASSERT_EQ(flag_name(f), std::nullopt); +} + +TEST(FlagNames, CompileTimeFlagName) { + static_assert(flag_name() == "TWO"); +} + +} // namespace android::test \ No newline at end of file diff --git a/libs/ftl/NamedEnum_test.cpp b/libs/ftl/NamedEnum_test.cpp new file mode 100644 index 0000000000..dff2b8aaa1 --- /dev/null +++ b/libs/ftl/NamedEnum_test.cpp @@ -0,0 +1,101 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace android { + +// Test enum class maximum enum value smaller than default maximum of 8. +enum class TestEnums { ZERO = 0x0, ONE = 0x1, TWO = 0x2, THREE = 0x3, SEVEN = 0x7 }; +// Big enum contains enum values greater than default maximum of 8. +enum class TestBigEnums { ZERO = 0x0, FIFTEEN = 0xF }; + +// Declared to specialize the maximum enum since the enum size exceeds 8 by default. +template <> +constexpr size_t NamedEnum::max = 16; + +namespace test { +using android::TestBigEnums; +using android::TestEnums; + +TEST(NamedEnum, RuntimeNamedEnum) { + TestEnums e = TestEnums::ZERO; + ASSERT_EQ(NamedEnum::enum_name(e), "ZERO"); + + e = TestEnums::ONE; + ASSERT_EQ(NamedEnum::enum_name(e), "ONE"); + + e = TestEnums::THREE; + ASSERT_EQ(NamedEnum::enum_name(e), "THREE"); + + e = TestEnums::SEVEN; + ASSERT_EQ(NamedEnum::enum_name(e), "SEVEN"); +} + +// Test big enum +TEST(NamedEnum, RuntimeBigNamedEnum) { + TestBigEnums e = TestBigEnums::ZERO; + ASSERT_EQ(NamedEnum::enum_name(e), "ZERO"); + + e = TestBigEnums::FIFTEEN; + ASSERT_EQ(NamedEnum::enum_name(e), "FIFTEEN"); +} + +TEST(NamedEnum, RuntimeNamedEnumAsString) { + TestEnums e = TestEnums::ZERO; + ASSERT_EQ(NamedEnum::string(e), "ZERO"); + + e = TestEnums::ONE; + ASSERT_EQ(NamedEnum::string(e), "ONE"); + + e = TestEnums::THREE; + ASSERT_EQ(NamedEnum::string(e), "THREE"); + + e = TestEnums::SEVEN; + ASSERT_EQ(NamedEnum::string(e), "SEVEN"); +} + +TEST(NamedEnum, RuntimeBigNamedEnumAsString) { + TestBigEnums e = TestBigEnums::ZERO; + ASSERT_EQ(NamedEnum::string(e), "ZERO"); + + e = TestBigEnums::FIFTEEN; + ASSERT_EQ(NamedEnum::string(e), "FIFTEEN"); +} + +TEST(NamedEnum, RuntimeUnknownNamedEnum) { + TestEnums e = static_cast(0x5); + ASSERT_EQ(NamedEnum::enum_name(e), std::nullopt); + e = static_cast(0x9); + ASSERT_EQ(NamedEnum::enum_name(e), std::nullopt); +} + +TEST(NamedEnum, RuntimeUnknownNamedEnumAsString) { + TestEnums e = static_cast(0x5); + ASSERT_EQ(NamedEnum::string(e), "05"); + e = static_cast(0x9); + ASSERT_EQ(NamedEnum::string(e, "0x%08x"), "0x00000009"); +} + +TEST(NamedEnum, CompileTimeFlagName) { + static_assert(NamedEnum::enum_name() == "TWO"); + static_assert(NamedEnum::enum_name() == "THREE"); +} + +} // namespace test + +} // namespace android diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 64203f78a8..2d8fff91da 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -51,6 +51,51 @@ cc_library_headers { ], } +// AIDL files that should be exposed to java +filegroup { + name: "guiconstants_aidl", + srcs: [ + "android/**/TouchOcclusionMode.aidl", + ], +} + +cc_library_static { + name: "libgui_window_info_static", + vendor_available: true, + host_supported: true, + srcs: [ + ":guiconstants_aidl", + "android/gui/FocusRequest.aidl", + "android/gui/InputApplicationInfo.aidl", + "android/gui/WindowInfo.aidl", + "WindowInfo.cpp", + ], + + shared_libs: [ + "libbinder", + ], + + local_include_dirs: [ + "include", + ], + + export_shared_lib_headers: [ + "libbinder", + ], + + static_libs: [ + "libui-types", + ], + + aidl: { + export_aidl_headers: true + }, + + include_dirs: [ + "frameworks/native/include", + ], +} + filegroup { name: "libgui_aidl", srcs: ["aidl/**/*.aidl"], @@ -77,12 +122,15 @@ cc_library_static { "libbinder", ], + static_libs: [ + "libui-types", + ], + aidl: { export_aidl_headers: true } } - cc_library_shared { name: "libgui", vendor_available: true, @@ -96,9 +144,11 @@ cc_library_shared { static_libs: [ "libgui_aidl_static", + "libgui_window_info_static", ], export_static_lib_headers: [ "libgui_aidl_static", + "libgui_window_info_static", ], srcs: [ @@ -150,13 +200,11 @@ cc_library_shared { "libbinder", "libbufferhub", "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui. - "libinput", "libpdx_default_transport", ], export_shared_lib_headers: [ "libbinder", - "libinput", ], export_header_lib_headers: [ @@ -168,7 +216,6 @@ cc_library_shared { vendor: { cflags: [ "-DNO_BUFFERHUB", - "-DNO_INPUT", ], exclude_srcs: [ "BufferHubConsumer.cpp", @@ -178,7 +225,6 @@ cc_library_shared { "android.frameworks.bufferhub@1.0", "libbufferhub", "libbufferhubqueue", - "libinput", "libpdx_default_transport", ], }, diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 29701168e7..dbb1cb0c17 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -38,7 +38,7 @@ using namespace std::chrono_literals; namespace { -inline const char* toString(bool b) { +inline const char* boolToString(bool b) { return b ? "true" : "false"; } } // namespace @@ -513,7 +513,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64 " applyTransaction=%s mTimestamp=%" PRId64 "%s mPendingTransactions.size=%d" " graphicBufferId=%" PRIu64 "%s", - mSize.width, mSize.height, bufferItem.mFrameNumber, toString(applyTransaction), + mSize.width, mSize.height, bufferItem.mFrameNumber, boolToString(applyTransaction), bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "", static_cast(mPendingTransactions.size()), bufferItem.mGraphicBuffer->getId(), bufferItem.mAutoRefresh ? " mAutoRefresh" : ""); @@ -543,7 +543,7 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { mNumFrameAvailable + mNumAcquired - mPendingRelease.size()); BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s", item.mFrameNumber, - toString(nextTransactionSet)); + boolToString(nextTransactionSet)); processNextBufferLocked(nextTransactionSet /* useNextTransaction */); } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index d102e07623..001570c391 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -31,6 +31,9 @@ namespace android { +using gui::FocusRequest; +using gui::WindowInfoHandle; + layer_state_t::layer_state_t() : what(0), x(0), @@ -94,9 +97,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeFloat, color.r); SAFE_PARCEL(output.writeFloat, color.g); SAFE_PARCEL(output.writeFloat, color.b); -#ifndef NO_INPUT - SAFE_PARCEL(inputHandle->writeToParcel, &output); -#endif + SAFE_PARCEL(windowInfoHandle->writeToParcel, &output); SAFE_PARCEL(output.write, transparentRegion); SAFE_PARCEL(output.writeUint32, transform); SAFE_PARCEL(output.writeBool, transformToDisplayInverse); @@ -205,9 +206,7 @@ status_t layer_state_t::read(const Parcel& input) color.g = tmpFloat; SAFE_PARCEL(input.readFloat, &tmpFloat); color.b = tmpFloat; -#ifndef NO_INPUT - SAFE_PARCEL(inputHandle->readFromParcel, &input); -#endif + SAFE_PARCEL(windowInfoHandle->readFromParcel, &input); SAFE_PARCEL(input.read, transparentRegion); SAFE_PARCEL(input.readUint32, &transform); @@ -491,14 +490,10 @@ void layer_state_t::merge(const layer_state_t& other) { if (other.what & eHasListenerCallbacksChanged) { what |= eHasListenerCallbacksChanged; } - -#ifndef NO_INPUT if (other.what & eInputInfoChanged) { what |= eInputInfoChanged; - inputHandle = new InputWindowHandle(*other.inputHandle); + windowInfoHandle = new WindowInfoHandle(*other.windowInfoHandle); } -#endif - if (other.what & eCachedBufferChanged) { what |= eCachedBufferChanged; cachedBuffer = other.cachedBuffer; @@ -589,11 +584,9 @@ status_t layer_state_t::matrix22_t::read(const Parcel& input) { bool InputWindowCommands::merge(const InputWindowCommands& other) { bool changes = false; -#ifndef NO_INPUT changes |= !other.focusRequests.empty(); focusRequests.insert(focusRequests.end(), std::make_move_iterator(other.focusRequests.begin()), std::make_move_iterator(other.focusRequests.end())); -#endif changes |= other.syncInputWindows && !syncInputWindows; syncInputWindows |= other.syncInputWindows; return changes; @@ -601,31 +594,23 @@ bool InputWindowCommands::merge(const InputWindowCommands& other) { bool InputWindowCommands::empty() const { bool empty = true; -#ifndef NO_INPUT empty = focusRequests.empty() && !syncInputWindows; -#endif return empty; } void InputWindowCommands::clear() { -#ifndef NO_INPUT focusRequests.clear(); -#endif syncInputWindows = false; } status_t InputWindowCommands::write(Parcel& output) const { -#ifndef NO_INPUT SAFE_PARCEL(output.writeParcelableVector, focusRequests); -#endif SAFE_PARCEL(output.writeBool, syncInputWindows); return NO_ERROR; } status_t InputWindowCommands::read(const Parcel& input) { -#ifndef NO_INPUT SAFE_PARCEL(input.readParcelableVector, &focusRequests); -#endif SAFE_PARCEL(input.readBool, &syncInputWindows); return NO_ERROR; } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 3118c72276..ec03c2105b 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -39,14 +39,11 @@ #include #include #include +#include #include #include #include -#ifndef NO_INPUT -#include -#endif - #include // This server size should always be smaller than the server cache size @@ -54,6 +51,9 @@ namespace android { +using gui::FocusRequest; +using gui::WindowInfo; +using gui::WindowInfoHandle; using ui::ColorMode; // --------------------------------------------------------------------------- @@ -1491,16 +1491,14 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame return *this; } -#ifndef NO_INPUT SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo( - const sp& sc, - const InputWindowInfo& info) { + const sp& sc, const WindowInfo& info) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } - s->inputHandle = new InputWindowHandle(info); + s->windowInfoHandle = new WindowInfoHandle(info); s->what |= layer_state_t::eInputInfoChanged; return *this; } @@ -1516,8 +1514,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::syncInpu return *this; } -#endif - SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorTransform( const sp& sc, const mat3& matrix, const vec3& translation) { layer_state_t* s = getLayerState(sc); diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp new file mode 100644 index 0000000000..ff0bb8aa55 --- /dev/null +++ b/libs/gui/WindowInfo.cpp @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2011 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 +#define LOG_TAG "WindowInfo" +#define LOG_NDEBUG 0 + +#include +#include +#include + +#include + +namespace android::gui { + +// --- WindowInfo --- +void WindowInfo::addTouchableRegion(const Rect& region) { + touchableRegion.orSelf(region); +} + +bool WindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const { + return touchableRegion.contains(x, y); +} + +bool WindowInfo::frameContainsPoint(int32_t x, int32_t y) const { + return x >= frameLeft && x < frameRight && y >= frameTop && y < frameBottom; +} + +bool WindowInfo::supportsSplitTouch() const { + return flags.test(Flag::SPLIT_TOUCH); +} + +bool WindowInfo::overlaps(const WindowInfo* other) const { + return frameLeft < other->frameRight && frameRight > other->frameLeft && + frameTop < other->frameBottom && frameBottom > other->frameTop; +} + +bool WindowInfo::operator==(const WindowInfo& info) const { + return info.token == token && info.id == id && info.name == name && info.flags == flags && + info.type == type && info.dispatchingTimeout == dispatchingTimeout && + info.frameLeft == frameLeft && info.frameTop == frameTop && + info.frameRight == frameRight && info.frameBottom == frameBottom && + info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor && + info.transform == transform && info.displayWidth == displayWidth && + info.displayHeight == displayHeight && + info.touchableRegion.hasSameRects(touchableRegion) && info.visible == visible && + info.trustedOverlay == trustedOverlay && info.focusable == focusable && + info.touchOcclusionMode == touchOcclusionMode && info.hasWallpaper == hasWallpaper && + info.paused == paused && info.ownerPid == ownerPid && info.ownerUid == ownerUid && + info.packageName == packageName && info.inputFeatures == inputFeatures && + info.displayId == displayId && info.portalToDisplayId == portalToDisplayId && + info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop && + info.applicationInfo == applicationInfo; +} + +status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + if (name.empty()) { + parcel->writeInt32(0); + return OK; + } + parcel->writeInt32(1); + + // clang-format off + status_t status = parcel->writeStrongBinder(token) ?: + parcel->writeInt64(dispatchingTimeout.count()) ?: + parcel->writeInt32(id) ?: + parcel->writeUtf8AsUtf16(name) ?: + parcel->writeInt32(flags.get()) ?: + parcel->writeInt32(static_cast>(type)) ?: + parcel->writeInt32(frameLeft) ?: + parcel->writeInt32(frameTop) ?: + parcel->writeInt32(frameRight) ?: + parcel->writeInt32(frameBottom) ?: + parcel->writeInt32(surfaceInset) ?: + parcel->writeFloat(globalScaleFactor) ?: + parcel->writeFloat(alpha) ?: + parcel->writeFloat(transform.dsdx()) ?: + parcel->writeFloat(transform.dtdx()) ?: + parcel->writeFloat(transform.tx()) ?: + parcel->writeFloat(transform.dtdy()) ?: + parcel->writeFloat(transform.dsdy()) ?: + parcel->writeFloat(transform.ty()) ?: + parcel->writeInt32(displayWidth) ?: + parcel->writeInt32(displayHeight) ?: + parcel->writeBool(visible) ?: + parcel->writeBool(focusable) ?: + parcel->writeBool(hasWallpaper) ?: + parcel->writeBool(paused) ?: + parcel->writeBool(trustedOverlay) ?: + parcel->writeInt32(static_cast(touchOcclusionMode)) ?: + parcel->writeInt32(ownerPid) ?: + parcel->writeInt32(ownerUid) ?: + parcel->writeUtf8AsUtf16(packageName) ?: + parcel->writeInt32(inputFeatures.get()) ?: + parcel->writeInt32(displayId) ?: + parcel->writeInt32(portalToDisplayId) ?: + applicationInfo.writeToParcel(parcel) ?: + parcel->write(touchableRegion) ?: + parcel->writeBool(replaceTouchableRegionWithCrop) ?: + parcel->writeStrongBinder(touchableRegionCropHandle.promote()); + // clang-format on + return status; +} + +status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + if (parcel->readInt32() == 0) { + return OK; + } + + token = parcel->readStrongBinder(); + dispatchingTimeout = static_cast(parcel->readInt64()); + status_t status = parcel->readInt32(&id) ?: parcel->readUtf8FromUtf16(&name); + if (status != OK) { + return status; + } + + flags = Flags(parcel->readInt32()); + type = static_cast(parcel->readInt32()); + float dsdx, dtdx, tx, dtdy, dsdy, ty; + int32_t touchOcclusionModeInt; + // clang-format off + status = parcel->readInt32(&frameLeft) ?: + parcel->readInt32(&frameTop) ?: + parcel->readInt32(&frameRight) ?: + parcel->readInt32(&frameBottom) ?: + parcel->readInt32(&surfaceInset) ?: + parcel->readFloat(&globalScaleFactor) ?: + parcel->readFloat(&alpha) ?: + parcel->readFloat(&dsdx) ?: + parcel->readFloat(&dtdx) ?: + parcel->readFloat(&tx) ?: + parcel->readFloat(&dtdy) ?: + parcel->readFloat(&dsdy) ?: + parcel->readFloat(&ty) ?: + parcel->readInt32(&displayWidth) ?: + parcel->readInt32(&displayHeight) ?: + parcel->readBool(&visible) ?: + parcel->readBool(&focusable) ?: + parcel->readBool(&hasWallpaper) ?: + parcel->readBool(&paused) ?: + parcel->readBool(&trustedOverlay) ?: + parcel->readInt32(&touchOcclusionModeInt) ?: + parcel->readInt32(&ownerPid) ?: + parcel->readInt32(&ownerUid) ?: + parcel->readUtf8FromUtf16(&packageName); + // clang-format on + + if (status != OK) { + return status; + } + + touchOcclusionMode = static_cast(touchOcclusionModeInt); + + inputFeatures = Flags(parcel->readInt32()); + // clang-format off + status = parcel->readInt32(&displayId) ?: + parcel->readInt32(&portalToDisplayId) ?: + applicationInfo.readFromParcel(parcel) ?: + parcel->read(touchableRegion) ?: + parcel->readBool(&replaceTouchableRegionWithCrop); + // clang-format on + + if (status != OK) { + return status; + } + + touchableRegionCropHandle = parcel->readStrongBinder(); + transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1}); + + return OK; +} + +// --- WindowInfoHandle --- + +WindowInfoHandle::WindowInfoHandle() {} + +WindowInfoHandle::~WindowInfoHandle() {} + +WindowInfoHandle::WindowInfoHandle(const WindowInfoHandle& other) : mInfo(other.mInfo) {} + +WindowInfoHandle::WindowInfoHandle(const WindowInfo& other) : mInfo(other) {} + +status_t WindowInfoHandle::writeToParcel(android::Parcel* parcel) const { + return mInfo.writeToParcel(parcel); +} + +status_t WindowInfoHandle::readFromParcel(const android::Parcel* parcel) { + return mInfo.readFromParcel(parcel); +} + +void WindowInfoHandle::releaseChannel() { + mInfo.token.clear(); +} + +sp WindowInfoHandle::getToken() const { + return mInfo.token; +} + +void WindowInfoHandle::updateFrom(sp handle) { + mInfo = handle->mInfo; +} +} // namespace android::gui diff --git a/libs/gui/android/gui/FocusRequest.aidl b/libs/gui/android/gui/FocusRequest.aidl new file mode 100644 index 0000000000..90186351c5 --- /dev/null +++ b/libs/gui/android/gui/FocusRequest.aidl @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2020, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.gui; + +/** @hide */ +parcelable FocusRequest { + /** + * Input channel token used to identify the window that should gain focus. + */ + IBinder token; + @utf8InCpp String windowName; + /** + * The token that the caller expects currently to be focused. If the + * specified token does not match the currently focused window, this request will be dropped. + * If the specified focused token matches the currently focused window, the call will succeed. + * Set this to "null" if this call should succeed no matter what the currently focused token + * is. + */ + @nullable IBinder focusedToken; + @utf8InCpp String focusedWindowName; + /** + * SYSTEM_TIME_MONOTONIC timestamp in nanos set by the client (wm) when requesting the focus + * change. This determines which request gets precedence if there is a focus change request + * from another source such as pointer down. + */ + long timestamp; + /** + * Display id associated with this request. + */ + int displayId; +} diff --git a/libs/gui/android/gui/InputApplicationInfo.aidl b/libs/gui/android/gui/InputApplicationInfo.aidl new file mode 100644 index 0000000000..c0fd666543 --- /dev/null +++ b/libs/gui/android/gui/InputApplicationInfo.aidl @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2020, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.gui; + +parcelable InputApplicationInfo { + @nullable IBinder token; + @utf8InCpp String name; + long dispatchingTimeoutMillis; +} diff --git a/libs/gui/android/gui/TouchOcclusionMode.aidl b/libs/gui/android/gui/TouchOcclusionMode.aidl new file mode 100644 index 0000000000..d91d052135 --- /dev/null +++ b/libs/gui/android/gui/TouchOcclusionMode.aidl @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2020, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.gui; + + +/** + * Touch occlusion modes: These modes represent how windows are taken into + * consideration in order to decide whether to block obscured touches or + * not. + * + * @hide + */ +@Backing(type="int") +enum TouchOcclusionMode { + /** + * Touches that pass through this window will be blocked if they are + * consumed by a different UID and this window is not trusted. + */ + BLOCK_UNTRUSTED, + + /** + * The window's opacity will be taken into consideration for touch + * occlusion rules if the touch passes through it and the window is not + * trusted. + */ + USE_OPACITY, + + /** + * The window won't count for touch occlusion rules if the touch passes + * through it. + */ + ALLOW +} diff --git a/libs/gui/android/gui/WindowInfo.aidl b/libs/gui/android/gui/WindowInfo.aidl new file mode 100644 index 0000000000..2c85d155a8 --- /dev/null +++ b/libs/gui/android/gui/WindowInfo.aidl @@ -0,0 +1,19 @@ +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.gui; + +parcelable WindowInfo cpp_header "gui/WindowInfo.h"; diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 8ec7e6d630..c0a2335885 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -24,9 +24,9 @@ #include #include #include +#include #include #include -#include #include #include #include diff --git a/libs/gui/include/gui/InputApplication.h b/libs/gui/include/gui/InputApplication.h new file mode 100644 index 0000000000..679c2a1754 --- /dev/null +++ b/libs/gui/include/gui/InputApplication.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef _UI_INPUT_APPLICATION_H +#define _UI_INPUT_APPLICATION_H + +#include + +#include + +#include +#include +#include + +#include +#include + +namespace android { + +/* + * Handle for an application that can receive input. + * + * Used by the native input dispatcher as a handle for the window manager objects + * that describe an application. + */ +class InputApplicationHandle { +public: + inline const gui::InputApplicationInfo* getInfo() const { return &mInfo; } + + inline std::string getName() const { return !mInfo.name.empty() ? mInfo.name : ""; } + + inline std::chrono::nanoseconds getDispatchingTimeout( + std::chrono::nanoseconds defaultValue) const { + return mInfo.token ? std::chrono::milliseconds(mInfo.dispatchingTimeoutMillis) + : defaultValue; + } + + inline sp getApplicationToken() const { return mInfo.token; } + + bool operator==(const InputApplicationHandle& other) const { + return getName() == other.getName() && getApplicationToken() == other.getApplicationToken(); + } + + bool operator!=(const InputApplicationHandle& other) const { return !(*this == other); } + + /** + * Requests that the state of this object be updated to reflect + * the most current available information about the application. + * + * This method should only be called from within the input dispatcher's + * critical section. + * + * Returns true on success, or false if the handle is no longer valid. + */ + virtual bool updateInfo() = 0; + +protected: + InputApplicationHandle() = default; + virtual ~InputApplicationHandle() = default; + + gui::InputApplicationInfo mInfo; +}; + +} // namespace android + +#endif // _UI_INPUT_APPLICATION_H diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 7961f4bd07..92de74a414 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -26,14 +26,12 @@ #include #include -#ifndef NO_INPUT -#include -#include (flag))); - return details::flag_names[idx]; -} - /* A class for handling flags defined by an enum or enum class in a type-safe way. */ template class Flags { @@ -94,7 +37,7 @@ class Flags { // further to avoid this restriction but in general we want to encourage the use of enums // anyways. static_assert(std::is_enum_v, "Flags type must be an enum"); - using U = typename std::underlying_type_t; + using U = std::underlying_type_t; public: constexpr Flags(F f) : mFlags(static_cast(f)) {} @@ -106,11 +49,10 @@ public: // should force them to be explicitly constructed from their underlying types to make full use // of the type checker. template - constexpr Flags(T t, typename std::enable_if_t, T>* = nullptr) - : mFlags(t) {} + constexpr Flags(T t, std::enable_if_t, T>* = nullptr) : mFlags(t) {} + template - explicit constexpr Flags(T t, - typename std::enable_if_t, T>* = nullptr) + explicit constexpr Flags(T t, std::enable_if_t, T>* = nullptr) : mFlags(t) {} class Iterator { @@ -229,16 +171,16 @@ public: bool first = true; U unstringified = 0; for (const F f : *this) { - std::optional flagString = flag_name(f); - if (flagString) { - appendFlag(result, flagString.value(), first); + if (const auto flagName = ftl::flag_name(f)) { + appendFlag(result, flagName.value(), first); } else { unstringified |= static_cast(f); } } if (unstringified != 0) { - appendFlag(result, base::StringPrintf("0x%08x", unstringified), first); + constexpr auto radix = sizeof(U) == 1 ? ftl::Radix::kBin : ftl::Radix::kHex; + appendFlag(result, ftl::to_string(unstringified, radix), first); } if (first) { @@ -265,15 +207,14 @@ private: // as flags. In order to use these, add them via a `using namespace` declaration. namespace flag_operators { -template >> +template >> inline Flags operator~(F f) { - using U = typename std::underlying_type_t; - return static_cast(~static_cast(f)); + return static_cast(~ftl::enum_cast(f)); } -template >> + +template >> Flags operator|(F lhs, F rhs) { - using U = typename std::underlying_type_t; - return static_cast(static_cast(lhs) | static_cast(rhs)); + return static_cast(ftl::enum_cast(lhs) | ftl::enum_cast(rhs)); } } // namespace flag_operators diff --git a/include/ftl/NamedEnum.h b/include/ftl/NamedEnum.h deleted file mode 100644 index 6e98feeb87..0000000000 --- a/include/ftl/NamedEnum.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include -#include -#include -#include - -#pragma once - -namespace android { - -namespace details { -template -constexpr std::optional enum_value_name() { - // Should look something like (but all on one line): - // std::optional - // android::details::enum_value_name() - // [E = android::test::TestEnums, V = android::test::TestEnums::ONE] - std::string_view view = __PRETTY_FUNCTION__; - size_t templateStart = view.rfind("["); - size_t templateEnd = view.rfind("]"); - if (templateStart == std::string::npos || templateEnd == std::string::npos) { - return std::nullopt; - } - - // Extract the template parameters without the enclosing braces. - // Example (cont'd): E = android::test::TestEnums, V = android::test::TestEnums::ONE - view = view.substr(templateStart + 1, templateEnd - templateStart - 1); - size_t valStart = view.rfind("V = "); - if (valStart == std::string::npos) { - return std::nullopt; - } - - // Example (cont'd): V = android::test::TestEnums::ONE - view = view.substr(valStart); - // Check invalid enum values with cast, like V = (android::test::TestEnums)8. - if (view.find('(') != std::string::npos) { - return std::nullopt; - } - size_t nameStart = view.rfind("::"); - if (nameStart == std::string::npos) { - return std::nullopt; - } - - // Chop off the initial "::" - nameStart += 2; - return view.substr(nameStart); -} - -template -constexpr auto generate_enum_values(std::integer_sequence seq) { - constexpr size_t count = seq.size(); - - std::array values{}; - for (size_t i = 0, v = 0; v < count; ++i) { - values[v++] = static_cast(T{0} + i); - } - - return values; -} - -template -inline constexpr auto enum_values = - generate_enum_values(std::make_integer_sequence, N>{}); - -template -constexpr auto generate_enum_names(std::index_sequence) noexcept { - return std::array, sizeof...(I)>{ - {enum_value_name[I]>()...}}; -} - -template -inline constexpr auto enum_names = generate_enum_names(std::make_index_sequence{}); - -} // namespace details - -class NamedEnum { -public: - // By default allowed enum value range is 0 ~ 7. - template - static constexpr size_t max = 8; - - template - static constexpr auto enum_name() { - using E = decltype(V); - return details::enum_value_name(); - } - - template - static constexpr std::optional enum_name(E val) { - auto idx = static_cast(val); - return idx < max ? details::enum_names>[idx] : std::nullopt; - } - - // Helper function for parsing enum value to string. - // Example : enum class TestEnums { ZERO = 0x0 }; - // NamedEnum::string(TestEnums::ZERO) returns string of "ZERO". - // Note the default maximum enum is 8, if the enum ID to be parsed if greater than 8 like 16, - // it should be declared to specialized the maximum enum by below: - // template <> constexpr size_t NamedEnum::max = 16; - // If the enum class definition is sparse and contains enum values starting from a large value, - // Do not specialize it to a large number to avoid performance issues. - // The recommended maximum enum number to specialize is 64. - template - static const std::string string(E val, const char* fallbackFormat = "%02d") { - std::string result; - std::optional enumString = enum_name(val); - result += enumString ? enumString.value() : base::StringPrintf(fallbackFormat, val); - return result; - } -}; - -} // namespace android diff --git a/include/ftl/enum.h b/include/ftl/enum.h new file mode 100644 index 0000000000..dfe3a0976b --- /dev/null +++ b/include/ftl/enum.h @@ -0,0 +1,299 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +// Returns the name of enumerator E::V (i.e. "V") as std::optional by parsing the +// compiler-generated string literal for the signature of this function. The function is defined in +// the global namespace with a short name and inferred return type to reduce bloat in the read-only +// data segment. +template +constexpr auto ftl_enum() { + static_assert(std::is_enum_v); + + using R = std::optional; + using namespace std::literals; + + // The "pretty" signature has the following format: + // + // auto ftl_enum() [E = android::test::Enum, V = android::test::Enum::kValue] + // + std::string_view view = __PRETTY_FUNCTION__; + const auto template_begin = view.rfind('['); + const auto template_end = view.rfind(']'); + if (template_begin == view.npos || template_end == view.npos) return R{}; + + // Extract the template parameters without the enclosing brackets. Example (cont'd): + // + // E = android::test::Enum, V = android::test::Enum::kValue + // + view = view.substr(template_begin + 1, template_end - template_begin - 1); + const auto value_begin = view.rfind("V = "sv); + if (value_begin == view.npos) return R{}; + + // Example (cont'd): + // + // V = android::test::Enum::kValue + // + view = view.substr(value_begin); + const auto name_begin = view.rfind("::"sv); + if (name_begin == view.npos) return R{}; + + // Chop off the leading "::". + const auto name = view.substr(name_begin + 2); + + // A value that is not enumerated has the format "Enum)42". + return name.find(')') == view.npos ? R{name} : R{}; +} + +namespace android::ftl { + +// Trait for determining whether a type is specifically a scoped enum or not. By definition, a +// scoped enum is one that is not implicitly convertible to its underlying type. +// +// TODO: Replace with std::is_scoped_enum in C++23. +// +template > +struct is_scoped_enum : std::false_type {}; + +template +struct is_scoped_enum : std::negation>> { +}; + +template +inline constexpr bool is_scoped_enum_v = is_scoped_enum::value; + +// Shorthand for casting an enumerator to its integral value. +// +// enum class E { A, B, C }; +// static_assert(ftl::enum_cast(E::B) == 1); +// +template +constexpr auto enum_cast(E v) { + return static_cast>(v); +} + +// Traits for retrieving an enum's range. An enum specifies its range by defining enumerators named +// ftl_first and ftl_last. If omitted, ftl_first defaults to 0, whereas ftl_last defaults to N - 1 +// where N is the bit width of the underlying type, but only if that type is unsigned, assuming the +// enumerators are flags. Also, note that unscoped enums must define both bounds, as casting out-of- +// range values results in undefined behavior if the underlying type is not fixed. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// static_assert(ftl::enum_begin_v == E::A); +// static_assert(ftl::enum_last_v == E::F); +// static_assert(ftl::enum_size_v == 6); +// +// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 }; +// +// static_assert(ftl::enum_begin_v == F{0}); +// static_assert(ftl::enum_last_v == F{15}); +// static_assert(ftl::enum_size_v == 16); +// +template +struct enum_begin { + static_assert(is_scoped_enum_v, "Missing ftl_first enumerator"); + static constexpr E value{0}; +}; + +template +struct enum_begin> { + static constexpr E value = E::ftl_first; +}; + +template +inline constexpr E enum_begin_v = enum_begin::value; + +template +struct enum_end { + using U = std::underlying_type_t; + static_assert(is_scoped_enum_v && std::is_unsigned_v, "Missing ftl_last enumerator"); + + static constexpr E value{std::numeric_limits::digits}; +}; + +template +struct enum_end> { + static constexpr E value = E{enum_cast(E::ftl_last) + 1}; +}; + +template +inline constexpr E enum_end_v = enum_end::value; + +template +inline constexpr E enum_last_v = E{enum_cast(enum_end_v) - 1}; + +template +struct enum_size { + static constexpr auto kBegin = enum_cast(enum_begin_v); + static constexpr auto kEnd = enum_cast(enum_end_v); + static_assert(kBegin < kEnd, "Invalid range"); + + static constexpr std::size_t value = kEnd - kBegin; + static_assert(value <= 64, "Excessive range size"); +}; + +template +inline constexpr std::size_t enum_size_v = enum_size::value; + +namespace details { + +template +struct Identity { + static constexpr auto value = V; +}; + +template +using make_enum_sequence = std::make_integer_sequence, enum_size_v>; + +template class = Identity, typename = make_enum_sequence> +struct EnumRange; + +template class F, typename T, T... Vs> +struct EnumRange> { + static constexpr auto kBegin = enum_cast(enum_begin_v); + static constexpr auto kSize = enum_size_v; + + using R = decltype(F::value); + const R values[kSize] = {F(Vs + kBegin)>::value...}; + + constexpr const auto* begin() const { return values; } + constexpr const auto* end() const { return values + kSize; } +}; + +template +struct EnumName { + static constexpr auto value = ftl_enum(); +}; + +template +struct FlagName { + using E = decltype(I); + using U = std::underlying_type_t; + + static constexpr E V{U{1} << enum_cast(I)}; + static constexpr auto value = ftl_enum(); +}; + +} // namespace details + +// Returns an iterable over the range of an enum. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// std::string string; +// for (E v : ftl::enum_range()) { +// string += ftl::enum_name(v).value_or("?"); +// } +// +// assert(string == "ABC??F"); +// +template +constexpr auto enum_range() { + return details::EnumRange{}; +} + +// Returns a stringified enumerator at compile time. +// +// enum class E { A, B, C }; +// static_assert(ftl::enum_name() == "B"); +// +template +constexpr std::string_view enum_name() { + constexpr auto kName = ftl_enum(); + static_assert(kName, "Unknown enumerator"); + return *kName; +} + +// Returns a stringified enumerator, possibly at compile time. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// static_assert(ftl::enum_name(E::C).value_or("?") == "C"); +// static_assert(ftl::enum_name(E{3}).value_or("?") == "?"); +// +template +constexpr std::optional enum_name(E v) { + const auto value = enum_cast(v); + + constexpr auto kBegin = enum_cast(enum_begin_v); + constexpr auto kLast = enum_cast(enum_last_v); + if (value < kBegin || value > kLast) return {}; + + constexpr auto kRange = details::EnumRange{}; + return kRange.values[value - kBegin]; +} + +// Returns a stringified flag enumerator, possibly at compile time. +// +// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 }; +// +// static_assert(ftl::flag_name(F::Z).value_or("?") == "Z"); +// static_assert(ftl::flag_name(F{0b111}).value_or("?") == "?"); +// +template +constexpr std::optional flag_name(E v) { + const auto value = enum_cast(v); + + // TODO: Replace with std::popcount and std::countr_zero in C++20. + if (__builtin_popcountl(value) != 1) return {}; + + constexpr auto kRange = details::EnumRange{}; + return kRange.values[__builtin_ctzl(value)]; +} + +// Returns a stringified enumerator, or its integral value if not named. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// assert(ftl::enum_string(E::C) == "C"); +// assert(ftl::enum_string(E{3}) == "3"); +// +template +inline std::string enum_string(E v) { + if (const auto name = enum_name(v)) { + return std::string(*name); + } + return to_string(enum_cast(v)); +} + +// Returns a stringified flag enumerator, or its integral value if not named. +// +// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 }; +// +// assert(ftl::flag_string(F::Z) == "Z"); +// assert(ftl::flag_string(F{7}) == "0b111"); +// +template +inline std::string flag_string(E v) { + if (const auto name = flag_name(v)) { + return std::string(*name); + } + constexpr auto radix = sizeof(E) == 1 ? Radix::kBin : Radix::kHex; + return to_string(enum_cast(v), radix); +} + +} // namespace android::ftl diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h index a6213f3ddd..9148fee532 100644 --- a/include/input/DisplayViewport.h +++ b/include/input/DisplayViewport.h @@ -18,7 +18,8 @@ #define _LIBINPUT_DISPLAY_VIEWPORT_H #include -#include +#include +#include #include #include @@ -44,6 +45,8 @@ enum class ViewportType : int32_t { INTERNAL = 1, EXTERNAL = 2, VIRTUAL = 3, + + ftl_last = VIRTUAL }; /* @@ -132,9 +135,8 @@ struct DisplayViewport { "physicalFrame=[%d, %d, %d, %d], " "deviceSize=[%d, %d], " "isActive=[%d]", - NamedEnum::string(type).c_str(), displayId, uniqueId.c_str(), - physicalPort ? StringPrintf("%" PRIu8, *physicalPort).c_str() - : "", + ftl::enum_string(type).c_str(), displayId, uniqueId.c_str(), + physicalPort ? ftl::to_string(*physicalPort).c_str() : "", orientation, logicalLeft, logicalTop, logicalRight, logicalBottom, physicalLeft, physicalTop, physicalRight, physicalBottom, deviceWidth, deviceHeight, isActive); diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h index 7f0324a4a8..22aae196c6 100644 --- a/include/input/InputDevice.h +++ b/include/input/InputDevice.h @@ -84,6 +84,9 @@ enum class InputDeviceSensorType : int32_t { GAME_ROTATION_VECTOR = ASENSOR_TYPE_GAME_ROTATION_VECTOR, GYROSCOPE_UNCALIBRATED = ASENSOR_TYPE_GYROSCOPE_UNCALIBRATED, SIGNIFICANT_MOTION = ASENSOR_TYPE_SIGNIFICANT_MOTION, + + ftl_first = ACCELEROMETER, + ftl_last = SIGNIFICANT_MOTION }; enum class InputDeviceSensorAccuracy : int32_t { @@ -105,6 +108,8 @@ enum class InputDeviceLightType : int32_t { PLAYER_ID = 1, RGB = 2, MULTI_COLOR = 3, + + ftl_last = MULTI_COLOR }; struct InputDeviceSensorInfo { diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 9a150eb0e2..7632b30bd2 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -73,6 +73,8 @@ struct InputMessage { DRAG, TIMELINE, TOUCH_MODE, + + ftl_last = TOUCH_MODE }; struct Header { diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 3026921044..5a80ad067c 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -14,10 +14,10 @@ cc_test { address: true, }, srcs: [ - "cast_test.cpp", "Flags_test.cpp", + "cast_test.cpp", + "enum_test.cpp", "future_test.cpp", - "NamedEnum_test.cpp", "small_map_test.cpp", "small_vector_test.cpp", "static_vector_test.cpp", diff --git a/libs/ftl/Flags_test.cpp b/libs/ftl/Flags_test.cpp index 8c00b5299b..d241fa272a 100644 --- a/libs/ftl/Flags_test.cpp +++ b/libs/ftl/Flags_test.cpp @@ -23,7 +23,7 @@ namespace android::test { using namespace android::flag_operators; -enum class TestFlags { ONE = 0x1, TWO = 0x2, THREE = 0x4 }; +enum class TestFlags : uint8_t { ONE = 0x1, TWO = 0x2, THREE = 0x4 }; TEST(Flags, Test) { Flags flags = TestFlags::ONE; @@ -165,7 +165,7 @@ TEST(Flags, String_KnownValues) { TEST(Flags, String_UnknownValues) { auto flags = Flags(0b1011); - ASSERT_EQ(flags.string(), "ONE | TWO | 0x00000008"); + ASSERT_EQ(flags.string(), "ONE | TWO | 0b1000"); } TEST(FlagsIterator, IteratesOverAllFlags) { @@ -210,18 +210,4 @@ TEST(FlagsIterator, PreFixIncrement) { ASSERT_EQ(++iter, flags.end()); } -TEST(FlagNames, RuntimeFlagName) { - TestFlags f = TestFlags::ONE; - ASSERT_EQ(flag_name(f), "ONE"); -} - -TEST(FlagNames, RuntimeUnknownFlagName) { - TestFlags f = static_cast(0x8); - ASSERT_EQ(flag_name(f), std::nullopt); -} - -TEST(FlagNames, CompileTimeFlagName) { - static_assert(flag_name() == "TWO"); -} - -} // namespace android::test \ No newline at end of file +} // namespace android::test diff --git a/libs/ftl/NamedEnum_test.cpp b/libs/ftl/NamedEnum_test.cpp deleted file mode 100644 index dff2b8aaa1..0000000000 --- a/libs/ftl/NamedEnum_test.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -namespace android { - -// Test enum class maximum enum value smaller than default maximum of 8. -enum class TestEnums { ZERO = 0x0, ONE = 0x1, TWO = 0x2, THREE = 0x3, SEVEN = 0x7 }; -// Big enum contains enum values greater than default maximum of 8. -enum class TestBigEnums { ZERO = 0x0, FIFTEEN = 0xF }; - -// Declared to specialize the maximum enum since the enum size exceeds 8 by default. -template <> -constexpr size_t NamedEnum::max = 16; - -namespace test { -using android::TestBigEnums; -using android::TestEnums; - -TEST(NamedEnum, RuntimeNamedEnum) { - TestEnums e = TestEnums::ZERO; - ASSERT_EQ(NamedEnum::enum_name(e), "ZERO"); - - e = TestEnums::ONE; - ASSERT_EQ(NamedEnum::enum_name(e), "ONE"); - - e = TestEnums::THREE; - ASSERT_EQ(NamedEnum::enum_name(e), "THREE"); - - e = TestEnums::SEVEN; - ASSERT_EQ(NamedEnum::enum_name(e), "SEVEN"); -} - -// Test big enum -TEST(NamedEnum, RuntimeBigNamedEnum) { - TestBigEnums e = TestBigEnums::ZERO; - ASSERT_EQ(NamedEnum::enum_name(e), "ZERO"); - - e = TestBigEnums::FIFTEEN; - ASSERT_EQ(NamedEnum::enum_name(e), "FIFTEEN"); -} - -TEST(NamedEnum, RuntimeNamedEnumAsString) { - TestEnums e = TestEnums::ZERO; - ASSERT_EQ(NamedEnum::string(e), "ZERO"); - - e = TestEnums::ONE; - ASSERT_EQ(NamedEnum::string(e), "ONE"); - - e = TestEnums::THREE; - ASSERT_EQ(NamedEnum::string(e), "THREE"); - - e = TestEnums::SEVEN; - ASSERT_EQ(NamedEnum::string(e), "SEVEN"); -} - -TEST(NamedEnum, RuntimeBigNamedEnumAsString) { - TestBigEnums e = TestBigEnums::ZERO; - ASSERT_EQ(NamedEnum::string(e), "ZERO"); - - e = TestBigEnums::FIFTEEN; - ASSERT_EQ(NamedEnum::string(e), "FIFTEEN"); -} - -TEST(NamedEnum, RuntimeUnknownNamedEnum) { - TestEnums e = static_cast(0x5); - ASSERT_EQ(NamedEnum::enum_name(e), std::nullopt); - e = static_cast(0x9); - ASSERT_EQ(NamedEnum::enum_name(e), std::nullopt); -} - -TEST(NamedEnum, RuntimeUnknownNamedEnumAsString) { - TestEnums e = static_cast(0x5); - ASSERT_EQ(NamedEnum::string(e), "05"); - e = static_cast(0x9); - ASSERT_EQ(NamedEnum::string(e, "0x%08x"), "0x00000009"); -} - -TEST(NamedEnum, CompileTimeFlagName) { - static_assert(NamedEnum::enum_name() == "TWO"); - static_assert(NamedEnum::enum_name() == "THREE"); -} - -} // namespace test - -} // namespace android diff --git a/libs/ftl/enum_test.cpp b/libs/ftl/enum_test.cpp new file mode 100644 index 0000000000..1fd43abbc6 --- /dev/null +++ b/libs/ftl/enum_test.cpp @@ -0,0 +1,164 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace android::test { + +// Keep in sync with example usage in header file. +namespace { + +enum class E { A, B, C, F = 5, ftl_last = F }; + +static_assert(ftl::enum_begin_v == E::A); +static_assert(ftl::enum_last_v == E::F); +static_assert(ftl::enum_size_v == 6); + +static_assert(ftl::enum_name() == "B"); +static_assert(ftl::enum_name() == "F"); +static_assert(ftl::enum_name(E::C).value_or("?") == "C"); +static_assert(ftl::enum_name(E{3}).value_or("?") == "?"); + +enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 }; + +static_assert(ftl::enum_begin_v == F{0}); +static_assert(ftl::enum_last_v == F{15}); +static_assert(ftl::enum_size_v == 16); + +static_assert(ftl::flag_name(F::Z).value_or("?") == "Z"); +static_assert(ftl::flag_name(F{0b111}).value_or("?") == "?"); + +// If a scoped enum is unsigned, its implicit range corresponds to its bit indices. +enum class Flags : std::uint8_t { + kNone = 0, + kFlag1 = 0b0000'0010, + kFlag4 = 0b0001'0000, + kFlag7 = 0b1000'0000, + kMask = kFlag1 | kFlag4 | kFlag7, + kAll = 0b1111'1111 +}; + +static_assert(ftl::enum_begin_v == Flags{0}); +static_assert(ftl::enum_last_v == Flags{7}); +static_assert(ftl::enum_size_v == 8); + +static_assert(ftl::enum_name() == "kNone"); +static_assert(ftl::enum_name() == "kFlag4"); +static_assert(ftl::enum_name() == "kFlag7"); + +// Though not flags, the enumerators are within the implicit range of bit indices. +enum class Planet : std::uint8_t { + kMercury, + kVenus, + kEarth, + kMars, + kJupiter, + kSaturn, + kUranus, + kNeptune +}; + +constexpr Planet kPluto{ftl::enum_cast(Planet::kNeptune) + 1}; // Honorable mention. + +static_assert(ftl::enum_begin_v == Planet::kMercury); +static_assert(ftl::enum_last_v == Planet::kNeptune); +static_assert(ftl::enum_size_v == 8); + +static_assert(ftl::enum_name() == "kMercury"); +static_assert(ftl::enum_name() == "kSaturn"); + +// Unscoped enum must define explicit range, even if the underlying type is fixed. +enum Temperature : int { + kRoom = 20, + kFridge = 4, + kFreezer = -18, + + ftl_first = kFreezer, + ftl_last = kRoom +}; + +static_assert(ftl::enum_begin_v == kFreezer); +static_assert(ftl::enum_last_v == kRoom); +static_assert(ftl::enum_size_v == 39); + +static_assert(ftl::enum_name() == "kFreezer"); +static_assert(ftl::enum_name() == "kFridge"); +static_assert(ftl::enum_name() == "kRoom"); + +} // namespace + +TEST(Enum, Range) { + std::string string; + for (E v : ftl::enum_range()) { + string += ftl::enum_name(v).value_or("?"); + } + EXPECT_EQ(string, "ABC??F"); +} + +TEST(Enum, Name) { + { + EXPECT_EQ(ftl::flag_name(Flags::kFlag1), "kFlag1"); + EXPECT_EQ(ftl::flag_name(Flags::kFlag7), "kFlag7"); + + EXPECT_EQ(ftl::flag_name(Flags::kNone), std::nullopt); + EXPECT_EQ(ftl::flag_name(Flags::kMask), std::nullopt); + EXPECT_EQ(ftl::flag_name(Flags::kAll), std::nullopt); + } + { + EXPECT_EQ(ftl::enum_name(Planet::kEarth), "kEarth"); + EXPECT_EQ(ftl::enum_name(Planet::kNeptune), "kNeptune"); + + EXPECT_EQ(ftl::enum_name(kPluto), std::nullopt); + } + { + EXPECT_EQ(ftl::enum_name(kRoom), "kRoom"); + EXPECT_EQ(ftl::enum_name(kFridge), "kFridge"); + EXPECT_EQ(ftl::enum_name(kFreezer), "kFreezer"); + + EXPECT_EQ(ftl::enum_name(static_cast(-30)), std::nullopt); + EXPECT_EQ(ftl::enum_name(static_cast(0)), std::nullopt); + EXPECT_EQ(ftl::enum_name(static_cast(100)), std::nullopt); + } +} + +TEST(Enum, String) { + { + EXPECT_EQ(ftl::flag_string(Flags::kFlag1), "kFlag1"); + EXPECT_EQ(ftl::flag_string(Flags::kFlag7), "kFlag7"); + + EXPECT_EQ(ftl::flag_string(Flags::kNone), "0b0"); + EXPECT_EQ(ftl::flag_string(Flags::kMask), "0b10010010"); + EXPECT_EQ(ftl::flag_string(Flags::kAll), "0b11111111"); + } + { + EXPECT_EQ(ftl::enum_string(Planet::kEarth), "kEarth"); + EXPECT_EQ(ftl::enum_string(Planet::kNeptune), "kNeptune"); + + EXPECT_EQ(ftl::enum_string(kPluto), "8"); + } + { + EXPECT_EQ(ftl::enum_string(kRoom), "kRoom"); + EXPECT_EQ(ftl::enum_string(kFridge), "kFridge"); + EXPECT_EQ(ftl::enum_string(kFreezer), "kFreezer"); + + EXPECT_EQ(ftl::enum_string(static_cast(-30)), "-30"); + EXPECT_EQ(ftl::enum_string(static_cast(0)), "0"); + EXPECT_EQ(ftl::enum_string(static_cast(100)), "100"); + } +} + +} // namespace android::test diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index f090c63228..47f6c05bff 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -71,8 +71,9 @@ struct WindowInfo : public Parcelable { SLIPPERY = 0x20000000, LAYOUT_ATTACHED_IN_DECOR = 0x40000000, DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000, - }; // Window types from WindowManager.LayoutParams + }; + // Window types from WindowManager.LayoutParams enum class Type : int32_t { UNKNOWN = 0, FIRST_APPLICATION_WINDOW = 1, @@ -87,40 +88,50 @@ struct WindowInfo : public Parcelable { APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3, APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4, LAST_SUB_WINDOW = 1999, - FIRST_SYSTEM_WINDOW = 2000, - STATUS_BAR = FIRST_SYSTEM_WINDOW, - SEARCH_BAR = FIRST_SYSTEM_WINDOW + 1, - PHONE = FIRST_SYSTEM_WINDOW + 2, - SYSTEM_ALERT = FIRST_SYSTEM_WINDOW + 3, - KEYGUARD = FIRST_SYSTEM_WINDOW + 4, - TOAST = FIRST_SYSTEM_WINDOW + 5, - SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 6, - PRIORITY_PHONE = FIRST_SYSTEM_WINDOW + 7, - SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW + 8, - KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW + 9, - SYSTEM_ERROR = FIRST_SYSTEM_WINDOW + 10, - INPUT_METHOD = FIRST_SYSTEM_WINDOW + 11, - INPUT_METHOD_DIALOG = FIRST_SYSTEM_WINDOW + 12, - WALLPAPER = FIRST_SYSTEM_WINDOW + 13, - STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW + 14, - SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 15, - DRAG = FIRST_SYSTEM_WINDOW + 16, - STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW + 17, - POINTER = FIRST_SYSTEM_WINDOW + 18, - NAVIGATION_BAR = FIRST_SYSTEM_WINDOW + 19, - VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW + 20, - BOOT_PROGRESS = FIRST_SYSTEM_WINDOW + 21, - INPUT_CONSUMER = FIRST_SYSTEM_WINDOW + 22, - NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW + 24, - MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 27, - ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW + 32, - DOCK_DIVIDER = FIRST_SYSTEM_WINDOW + 34, - ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 39, - NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40, + +#define FIRST_SYSTEM_WINDOW_ 2000 + + STATUS_BAR = FIRST_SYSTEM_WINDOW_, + SEARCH_BAR = FIRST_SYSTEM_WINDOW_ + 1, + PHONE = FIRST_SYSTEM_WINDOW_ + 2, + SYSTEM_ALERT = FIRST_SYSTEM_WINDOW_ + 3, + KEYGUARD = FIRST_SYSTEM_WINDOW_ + 4, + TOAST = FIRST_SYSTEM_WINDOW_ + 5, + SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW_ + 6, + PRIORITY_PHONE = FIRST_SYSTEM_WINDOW_ + 7, + SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW_ + 8, + KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW_ + 9, + SYSTEM_ERROR = FIRST_SYSTEM_WINDOW_ + 10, + INPUT_METHOD = FIRST_SYSTEM_WINDOW_ + 11, + INPUT_METHOD_DIALOG = FIRST_SYSTEM_WINDOW_ + 12, + WALLPAPER = FIRST_SYSTEM_WINDOW_ + 13, + STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW_ + 14, + SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW_ + 15, + DRAG = FIRST_SYSTEM_WINDOW_ + 16, + STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW_ + 17, + POINTER = FIRST_SYSTEM_WINDOW_ + 18, + NAVIGATION_BAR = FIRST_SYSTEM_WINDOW_ + 19, + VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW_ + 20, + BOOT_PROGRESS = FIRST_SYSTEM_WINDOW_ + 21, + INPUT_CONSUMER = FIRST_SYSTEM_WINDOW_ + 22, + NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW_ + 24, + MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW_ + 27, + ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW_ + 32, + DOCK_DIVIDER = FIRST_SYSTEM_WINDOW_ + 34, + ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW_ + 39, + NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW_ + 40, + + FIRST_SYSTEM_WINDOW = FIRST_SYSTEM_WINDOW_, LAST_SYSTEM_WINDOW = 2999, + +#undef FIRST_SYSTEM_WINDOW_ + + // Small range to limit LUT size. + ftl_first = FIRST_SYSTEM_WINDOW, + ftl_last = FIRST_SYSTEM_WINDOW + 15 }; - enum class Feature { + enum class Feature : uint32_t { DISABLE_TOUCH_PAD_GESTURES = 0x00000001, NO_INPUT_CHANNEL = 0x00000002, DISABLE_USER_ACTIVITY = 0x00000004, @@ -265,4 +276,4 @@ protected: WindowInfo mInfo; }; -} // namespace android::gui \ No newline at end of file +} // namespace android::gui diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp index 220c8e1e6e..69ae9a02ec 100644 --- a/libs/input/InputDevice.cpp +++ b/libs/input/InputDevice.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include @@ -228,7 +228,7 @@ void InputDeviceInfo::addMotionRange(const MotionRange& range) { void InputDeviceInfo::addSensorInfo(const InputDeviceSensorInfo& info) { if (mSensors.find(info.type) != mSensors.end()) { ALOGW("Sensor type %s already exists, will be replaced by new sensor added.", - NamedEnum::string(info.type).c_str()); + ftl::enum_string(info.type).c_str()); } mSensors.insert_or_assign(info.type, info); } diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 1e93dfb488..91ab008161 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -30,10 +30,10 @@ static constexpr bool DEBUG_TRANSPORT_ACTIONS = false; #include #include #include +#include #include #include -#include #include using android::base::StringPrintf; @@ -714,7 +714,7 @@ android::base::Result InputPublisher::receiveC } ALOGE("channel '%s' publisher ~ Received unexpected %s message from consumer", - mChannel->getName().c_str(), NamedEnum::string(msg.header.type).c_str()); + mChannel->getName().c_str(), ftl::enum_string(msg.header.type).c_str()); return android::base::Error(UNKNOWN_ERROR); } @@ -856,7 +856,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consum case InputMessage::Type::TIMELINE: { LOG_ALWAYS_FATAL("Consumed a %s message, which should never be seen by " "InputConsumer!", - NamedEnum::string(mMsg.header.type).c_str()); + ftl::enum_string(mMsg.header.type).c_str()); break; } @@ -1449,14 +1449,14 @@ std::string InputConsumer::dump() const { out = out + "mChannel = " + mChannel->getName() + "\n"; out = out + "mMsgDeferred: " + toString(mMsgDeferred) + "\n"; if (mMsgDeferred) { - out = out + "mMsg : " + NamedEnum::string(mMsg.header.type) + "\n"; + out = out + "mMsg : " + ftl::enum_string(mMsg.header.type) + "\n"; } out += "Batches:\n"; for (const Batch& batch : mBatches) { out += " Batch:\n"; for (const InputMessage& msg : batch.samples) { out += android::base::StringPrintf(" Message %" PRIu32 ": %s ", msg.header.seq, - NamedEnum::string(msg.header.type).c_str()); + ftl::enum_string(msg.header.type).c_str()); switch (msg.header.type) { case InputMessage::Type::KEY: { out += android::base::StringPrintf("action=%s keycode=%" PRId32, diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp index c365ab070e..7c25cda9ac 100644 --- a/libs/input/KeyLayoutMap.cpp +++ b/libs/input/KeyLayoutMap.cpp @@ -16,10 +16,8 @@ #define LOG_TAG "KeyLayoutMap" -#include - #include -#include +#include #include #include #include @@ -28,6 +26,10 @@ #include #include +#include +#include +#include + // Enables debug output for the parser. #define DEBUG_PARSER 0 @@ -39,37 +41,39 @@ namespace android { +namespace { -static const char* WHITESPACE = " \t\r"; - -#define SENSOR_ENTRY(type) NamedEnum::string(type), type -static const std::unordered_map SENSOR_LIST = - {{SENSOR_ENTRY(InputDeviceSensorType::ACCELEROMETER)}, - {SENSOR_ENTRY(InputDeviceSensorType::MAGNETIC_FIELD)}, - {SENSOR_ENTRY(InputDeviceSensorType::ORIENTATION)}, - {SENSOR_ENTRY(InputDeviceSensorType::GYROSCOPE)}, - {SENSOR_ENTRY(InputDeviceSensorType::LIGHT)}, - {SENSOR_ENTRY(InputDeviceSensorType::PRESSURE)}, - {SENSOR_ENTRY(InputDeviceSensorType::TEMPERATURE)}, - {SENSOR_ENTRY(InputDeviceSensorType::PROXIMITY)}, - {SENSOR_ENTRY(InputDeviceSensorType::GRAVITY)}, - {SENSOR_ENTRY(InputDeviceSensorType::LINEAR_ACCELERATION)}, - {SENSOR_ENTRY(InputDeviceSensorType::ROTATION_VECTOR)}, - {SENSOR_ENTRY(InputDeviceSensorType::RELATIVE_HUMIDITY)}, - {SENSOR_ENTRY(InputDeviceSensorType::AMBIENT_TEMPERATURE)}, - {SENSOR_ENTRY(InputDeviceSensorType::MAGNETIC_FIELD_UNCALIBRATED)}, - {SENSOR_ENTRY(InputDeviceSensorType::GAME_ROTATION_VECTOR)}, - {SENSOR_ENTRY(InputDeviceSensorType::GYROSCOPE_UNCALIBRATED)}, - {SENSOR_ENTRY(InputDeviceSensorType::SIGNIFICANT_MOTION)}}; - -// --- KeyLayoutMap --- - -KeyLayoutMap::KeyLayoutMap() { -} +constexpr const char* WHITESPACE = " \t\r"; -KeyLayoutMap::~KeyLayoutMap() { +template +constexpr auto sensorPair() { + return std::make_pair(ftl::enum_name(), S); } +static const std::unordered_map SENSOR_LIST = + {sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair()}; + +} // namespace + +KeyLayoutMap::KeyLayoutMap() = default; +KeyLayoutMap::~KeyLayoutMap() = default; + base::Result> KeyLayoutMap::loadContents(const std::string& filename, const char* contents) { Tokenizer* tokenizer; @@ -160,8 +164,8 @@ base::Result> KeyLayoutMap::mapSensor( const Sensor& sensor = it->second; #if DEBUG_MAPPING - ALOGD("mapSensor: absCode=%d, sensorType=0x%0x, sensorDataIndex=0x%x.", absCode, - NamedEnum::string(sensor.sensorType), sensor.sensorDataIndex); + ALOGD("mapSensor: absCode=%d, sensorType=%s, sensorDataIndex=0x%x.", absCode, + ftl::enum_string(sensor.sensorType).c_str(), sensor.sensorDataIndex); #endif return std::make_pair(sensor.sensorType, sensor.sensorDataIndex); } @@ -513,7 +517,7 @@ status_t KeyLayoutMap::Parser::parseLed() { } static std::optional getSensorType(const char* token) { - auto it = SENSOR_LIST.find(std::string(token)); + auto it = SENSOR_LIST.find(token); if (it == SENSOR_LIST.end()) { return std::nullopt; } @@ -581,8 +585,8 @@ status_t KeyLayoutMap::Parser::parseSensor() { int32_t sensorDataIndex = indexOpt.value(); #if DEBUG_PARSER - ALOGD("Parsed sensor: abs code=%d, sensorType=%d, sensorDataIndex=%d.", code, - NamedEnum::string(sensorType).c_str(), sensorDataIndex); + ALOGD("Parsed sensor: abs code=%d, sensorType=%s, sensorDataIndex=%d.", code, + ftl::enum_string(sensorType).c_str(), sensorDataIndex); #endif Sensor sensor; @@ -591,4 +595,5 @@ status_t KeyLayoutMap::Parser::parseSensor() { map.emplace(code, sensor); return NO_ERROR; } -}; + +} // namespace android diff --git a/services/inputflinger/InputReaderBase.cpp b/services/inputflinger/InputReaderBase.cpp index 05ef489133..a864cf8202 100644 --- a/services/inputflinger/InputReaderBase.cpp +++ b/services/inputflinger/InputReaderBase.cpp @@ -19,12 +19,12 @@ //#define LOG_NDEBUG 0 #include "InputReaderBase.h" -#include #include "input/DisplayViewport.h" #include "input/Input.h" -#include #include +#include +#include #define INDENT " " #define INDENT2 " " @@ -117,7 +117,7 @@ std::optional InputReaderConfiguration::getDisplayViewportByTyp } if (count > 1) { ALOGW("Found %zu viewports with type %s, but expected 1 at most", count, - NamedEnum::string(type).c_str()); + ftl::enum_string(type).c_str()); } return result; } diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index 547021ca22..5365a78b0a 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -40,6 +40,8 @@ struct EventEntry { POINTER_CAPTURE_CHANGED, DRAG, TOUCH_MODE_CHANGED, + + ftl_last = TOUCH_MODE_CHANGED }; int32_t id; diff --git a/services/inputflinger/dispatcher/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp index 4a75773201..600f02ba80 100644 --- a/services/inputflinger/dispatcher/FocusResolver.cpp +++ b/services/inputflinger/dispatcher/FocusResolver.cpp @@ -27,7 +27,7 @@ static constexpr bool DEBUG_FOCUS = false; #include #include -#include +#include #include #include @@ -65,7 +65,7 @@ std::optional FocusResolver::setInputWindows( if (result == Focusability::OK) { return std::nullopt; } - removeFocusReason = NamedEnum::string(result); + removeFocusReason = ftl::enum_string(result); } // We don't have a focused window or the currently focused window is no longer focusable. Check @@ -79,7 +79,7 @@ std::optional FocusResolver::setInputWindows( if (result == Focusability::OK) { return updateFocusedWindow(displayId, "Window became focusable. Previous reason: " + - NamedEnum::string(previousResult), + ftl::enum_string(previousResult), requestedFocus, request->windowName); } } @@ -116,7 +116,7 @@ std::optional FocusResolver::setFocusedWindow( request.token, request.windowName); } ALOGW("setFocusedWindow %s on display %" PRId32 " ignored, reason: %s", - request.windowName.c_str(), displayId, NamedEnum::string(result).c_str()); + request.windowName.c_str(), displayId, ftl::enum_string(result).c_str()); return std::nullopt; } @@ -134,7 +134,7 @@ std::optional FocusResolver::setFocusedWindow( // The requested window is not currently focusable. Wait for the window to become focusable // but remove focus from the current window so that input events can go into a pending queue // and be sent to the window when it becomes focused. - return updateFocusedWindow(displayId, "Waiting for window because " + NamedEnum::string(result), + return updateFocusedWindow(displayId, "Waiting for window because " + ftl::enum_string(result), nullptr); } @@ -212,7 +212,7 @@ std::string FocusResolver::dump() const { for (const auto& [displayId, request] : mFocusRequestByDisplay) { auto it = mLastFocusResultByDisplay.find(displayId); std::string result = - it != mLastFocusResultByDisplay.end() ? NamedEnum::string(it->second) : ""; + it != mLastFocusResultByDisplay.end() ? ftl::enum_string(it->second) : ""; dump += base::StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s' result='%s'\n", displayId, request.windowName.c_str(), result.c_str()); } diff --git a/services/inputflinger/dispatcher/FocusResolver.h b/services/inputflinger/dispatcher/FocusResolver.h index 1d6cd9a5fa..6d11a77aad 100644 --- a/services/inputflinger/dispatcher/FocusResolver.h +++ b/services/inputflinger/dispatcher/FocusResolver.h @@ -77,6 +77,8 @@ private: NO_WINDOW, NOT_FOCUSABLE, NOT_VISIBLE, + + ftl_last = NOT_VISIBLE }; // Checks if the window token can be focused on a display. The token can be focused if there is @@ -113,4 +115,4 @@ private: std::optional getFocusRequest(int32_t displayId); }; -} // namespace android::inputdispatcher \ No newline at end of file +} // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 92ba52c3f4..9da71925ce 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1151,7 +1152,7 @@ void InputDispatcher::dropInboundEventLocked(const EventEntry& entry, DropReason case EventEntry::Type::TOUCH_MODE_CHANGED: case EventEntry::Type::CONFIGURATION_CHANGED: case EventEntry::Type::DEVICE_RESET: { - LOG_ALWAYS_FATAL("Should not drop %s events", NamedEnum::string(entry.type).c_str()); + LOG_ALWAYS_FATAL("Should not drop %s events", ftl::enum_string(entry.type).c_str()); break; } } @@ -1573,7 +1574,7 @@ void InputDispatcher::dispatchSensorLocked(nsecs_t currentTime, ALOGD("notifySensorEvent eventTime=%" PRId64 ", hwTimestamp=%" PRId64 ", deviceId=%d, " "source=0x%x, sensorType=%s", entry->eventTime, entry->hwTimestamp, entry->deviceId, entry->source, - NamedEnum::string(entry->sensorType).c_str()); + ftl::enum_string(entry->sensorType).c_str()); } auto command = [this, entry]() REQUIRES(mLock) { scoped_unlock unlock(mLock); @@ -1590,7 +1591,7 @@ void InputDispatcher::dispatchSensorLocked(nsecs_t currentTime, bool InputDispatcher::flushSensor(int deviceId, InputDeviceSensorType sensorType) { if (DEBUG_OUTBOUND_EVENT_DETAILS) { ALOGD("flushSensor deviceId=%d, sensorType=%s", deviceId, - NamedEnum::string(sensorType).c_str()); + ftl::enum_string(sensorType).c_str()); } { // acquire lock std::scoped_lock _l(mLock); @@ -1811,7 +1812,7 @@ int32_t InputDispatcher::getTargetDisplayId(const EventEntry& entry) { case EventEntry::Type::DEVICE_RESET: case EventEntry::Type::SENSOR: case EventEntry::Type::DRAG: { - ALOGE("%s events do not have a target display", NamedEnum::string(entry.type).c_str()); + ALOGE("%s events do not have a target display", ftl::enum_string(entry.type).c_str()); return ADISPLAY_ID_NONE; } } @@ -1863,7 +1864,7 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked( if (focusedWindowHandle == nullptr && focusedApplicationHandle == nullptr) { ALOGI("Dropping %s event because there is no focused window or focused application in " "display %" PRId32 ".", - NamedEnum::string(entry.type).c_str(), displayId); + ftl::enum_string(entry.type).c_str(), displayId); return InputEventInjectionResult::FAILED; } @@ -1888,7 +1889,7 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked( } else if (currentTime > *mNoFocusedWindowTimeoutTime) { // Already raised ANR. Drop the event ALOGE("Dropping %s event because there is no focused window", - NamedEnum::string(entry.type).c_str()); + ftl::enum_string(entry.type).c_str()); return InputEventInjectionResult::FAILED; } else { // Still waiting for the focused window @@ -2676,8 +2677,7 @@ std::string InputDispatcher::dumpWindowForTouchOcclusion(const WindowInfo* info, "frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32 "], touchableRegion=%s, window={%s}, flags={%s}, inputFeatures={%s}, " "hasToken=%s, applicationInfo.name=%s, applicationInfo.token=%s\n", - (isTouchedWindow) ? "[TOUCHED] " : "", - NamedEnum::string(info->type, "%" PRId32).c_str(), + isTouchedWindow ? "[TOUCHED] " : "", ftl::enum_string(info->type).c_str(), info->packageName.c_str(), info->ownerUid, info->id, toString(info->touchOcclusionMode).c_str(), info->alpha, info->frameLeft, info->frameTop, info->frameRight, info->frameBottom, @@ -2804,7 +2804,7 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) { case EventEntry::Type::POINTER_CAPTURE_CHANGED: case EventEntry::Type::DRAG: { LOG_ALWAYS_FATAL("%s events are not user activity", - NamedEnum::string(eventEntry.type).c_str()); + ftl::enum_string(eventEntry.type).c_str()); break; } } @@ -2849,7 +2849,7 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, if (inputTarget.flags & InputTarget::FLAG_SPLIT) { LOG_ALWAYS_FATAL_IF(eventEntry->type != EventEntry::Type::MOTION, "Entry type %s should not have FLAG_SPLIT", - NamedEnum::string(eventEntry->type).c_str()); + ftl::enum_string(eventEntry->type).c_str()); const MotionEntry& originalMotionEntry = static_cast(*eventEntry); if (inputTarget.pointerIds.count() != originalMotionEntry.pointerCount) { @@ -3037,7 +3037,7 @@ void InputDispatcher::enqueueDispatchEntryLocked(const sp& connectio case EventEntry::Type::CONFIGURATION_CHANGED: case EventEntry::Type::DEVICE_RESET: { LOG_ALWAYS_FATAL("%s events should not go to apps", - NamedEnum::string(newEntry.type).c_str()); + ftl::enum_string(newEntry.type).c_str()); break; } } @@ -3276,7 +3276,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, case EventEntry::Type::DEVICE_RESET: case EventEntry::Type::SENSOR: { LOG_ALWAYS_FATAL("Should never start dispatch cycles for %s events", - NamedEnum::string(eventEntry.type).c_str()); + ftl::enum_string(eventEntry.type).c_str()); return; } } @@ -3592,14 +3592,14 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( case EventEntry::Type::POINTER_CAPTURE_CHANGED: case EventEntry::Type::DRAG: { LOG_ALWAYS_FATAL("Canceling %s events is not supported", - NamedEnum::string(cancelationEventEntry->type).c_str()); + ftl::enum_string(cancelationEventEntry->type).c_str()); break; } case EventEntry::Type::CONFIGURATION_CHANGED: case EventEntry::Type::DEVICE_RESET: case EventEntry::Type::SENSOR: { LOG_ALWAYS_FATAL("%s event should not be found inside Connections's queue", - NamedEnum::string(cancelationEventEntry->type).c_str()); + ftl::enum_string(cancelationEventEntry->type).c_str()); break; } } @@ -3659,7 +3659,7 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( case EventEntry::Type::SENSOR: case EventEntry::Type::DRAG: { LOG_ALWAYS_FATAL("%s event should not be found inside Connections's queue", - NamedEnum::string(downEventEntry->type).c_str()); + ftl::enum_string(downEventEntry->type).c_str()); break; } } @@ -4007,7 +4007,7 @@ void InputDispatcher::notifySensor(const NotifySensorArgs* args) { ALOGD("notifySensor - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, " " sensorType=%s", args->id, args->eventTime, args->deviceId, args->source, - NamedEnum::string(args->sensorType).c_str()); + ftl::enum_string(args->sensorType).c_str()); } bool needWake; @@ -5115,7 +5115,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { toString(windowInfo->hasWallpaper), toString(windowInfo->visible), windowInfo->alpha, windowInfo->flags.string().c_str(), - NamedEnum::string(windowInfo->type).c_str(), + ftl::enum_string(windowInfo->type).c_str(), windowInfo->frameLeft, windowInfo->frameTop, windowInfo->frameRight, windowInfo->frameBottom, windowInfo->globalScaleFactor, diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index 0f0ad0a102..d10f8b6605 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -263,7 +264,7 @@ static std::vector allFilesInPath(const std::filesystem:: */ static std::vector findSysfsNodes(const std::filesystem::path& sysfsRoot, SysfsClass clazz) { - std::string nodeStr = NamedEnum::string(clazz); + std::string nodeStr = ftl::enum_string(clazz); std::for_each(nodeStr.begin(), nodeStr.end(), [](char& c) { c = std::tolower(static_cast(c)); }); std::vector nodes; diff --git a/services/inputflinger/reader/controller/PeripheralController.cpp b/services/inputflinger/reader/controller/PeripheralController.cpp index 9c8a29a059..a6934960c9 100644 --- a/services/inputflinger/reader/controller/PeripheralController.cpp +++ b/services/inputflinger/reader/controller/PeripheralController.cpp @@ -17,9 +17,9 @@ #include #include -#include "../Macros.h" +#include -#include +#include "../Macros.h" #include "PeripheralController.h" // Log detailed debug messages about input device lights. @@ -286,7 +286,7 @@ void PeripheralController::dump(std::string& dump) { for (const auto& [lightId, light] : mLights) { dump += StringPrintf(INDENT4 "Id: %d", lightId); dump += StringPrintf(INDENT4 "Name: %s", light->name.c_str()); - dump += StringPrintf(INDENT4 "Type: %s", NamedEnum::string(light->type).c_str()); + dump += StringPrintf(INDENT4 "Type: %s", ftl::enum_string(light->type).c_str()); light->dump(dump); } } @@ -487,7 +487,7 @@ bool PeripheralController::setLightColor(int32_t lightId, int32_t color) { auto& light = it->second; if (DEBUG_LIGHT_DETAILS) { ALOGD("setLightColor lightId %d type %s color 0x%x", lightId, - NamedEnum::string(light->type).c_str(), color); + ftl::enum_string(light->type).c_str(), color); } return light->setLightColor(color); } @@ -501,7 +501,7 @@ std::optional PeripheralController::getLightColor(int32_t lightId) { std::optional color = light->getLightColor(); if (DEBUG_LIGHT_DETAILS) { ALOGD("getLightColor lightId %d type %s color 0x%x", lightId, - NamedEnum::string(light->type).c_str(), color.value_or(0)); + ftl::enum_string(light->type).c_str(), color.value_or(0)); } return color; } diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index 7a00bace6e..1f96294e96 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -146,6 +146,8 @@ enum class InputDeviceClass : uint32_t { enum class SysfsClass : uint32_t { POWER_SUPPLY = 0, LEDS = 1, + + ftl_last = LEDS }; enum class LightColor : uint32_t { diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.cpp b/services/inputflinger/reader/mapper/SensorInputMapper.cpp index a507632d0e..a1bd548403 100644 --- a/services/inputflinger/reader/mapper/SensorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/SensorInputMapper.cpp @@ -16,8 +16,9 @@ #include -#include "../Macros.h" +#include +#include "../Macros.h" #include "SensorInputMapper.h" // Log detailed debug messages about each sensor event notification to the dispatcher. @@ -93,7 +94,7 @@ void SensorInputMapper::dump(std::string& dump) { dump += StringPrintf(INDENT3 " mHasHardwareTimestamp %d\n", mHasHardwareTimestamp); dump += INDENT3 "Sensors:\n"; for (const auto& [sensorType, sensor] : mSensors) { - dump += StringPrintf(INDENT4 "%s\n", NamedEnum::string(sensorType).c_str()); + dump += StringPrintf(INDENT4 "%s\n", ftl::enum_string(sensorType).c_str()); dump += StringPrintf(INDENT5 "enabled: %d\n", sensor.enabled); dump += StringPrintf(INDENT5 "samplingPeriod: %lld\n", sensor.samplingPeriod.count()); dump += StringPrintf(INDENT5 "maxBatchReportLatency: %lld\n", @@ -208,10 +209,10 @@ SensorInputMapper::Sensor SensorInputMapper::createSensor(InputDeviceSensorType axis.max /* maxRange */, axis.scale /* resolution */, 0.0f /* power */, 0 /* minDelay */, 0 /* fifoReservedEventCount */, 0 /* fifoMaxEventCount */, - NamedEnum::string(sensorType), 0 /* maxDelay */, 0 /* flags */, + ftl::enum_string(sensorType), 0 /* maxDelay */, 0 /* flags */, getDeviceId()); - std::string prefix = "sensor." + NamedEnum::string(sensorType); + std::string prefix = "sensor." + ftl::enum_string(sensorType); transform(prefix.begin(), prefix.end(), prefix.begin(), ::tolower); int32_t reportingMode = 0; @@ -335,7 +336,7 @@ bool SensorInputMapper::enableSensor(InputDeviceSensorType sensorType, std::chrono::microseconds maxBatchReportLatency) { if (DEBUG_SENSOR_EVENT_DETAILS) { ALOGD("Enable Sensor %s samplingPeriod %lld maxBatchReportLatency %lld", - NamedEnum::string(sensorType).c_str(), samplingPeriod.count(), + ftl::enum_string(sensorType).c_str(), samplingPeriod.count(), maxBatchReportLatency.count()); } @@ -359,7 +360,7 @@ bool SensorInputMapper::enableSensor(InputDeviceSensorType sensorType, void SensorInputMapper::disableSensor(InputDeviceSensorType sensorType) { if (DEBUG_SENSOR_EVENT_DETAILS) { - ALOGD("Disable Sensor %s", NamedEnum::string(sensorType).c_str()); + ALOGD("Disable Sensor %s", ftl::enum_string(sensorType).c_str()); } if (!setSensorEnabled(sensorType, false /* enabled */)) { @@ -393,13 +394,12 @@ void SensorInputMapper::sync(nsecs_t when, bool force) { nsecs_t timestamp = mHasHardwareTimestamp ? mHardwareTimestamp : when; if (DEBUG_SENSOR_EVENT_DETAILS) { ALOGD("Sensor %s timestamp %" PRIu64 " values [%f %f %f]", - NamedEnum::string(sensorType).c_str(), timestamp, values[0], values[1], - values[2]); + ftl::enum_string(sensorType).c_str(), timestamp, values[0], values[1], values[2]); } if (sensor.lastSampleTimeNs.has_value() && timestamp - sensor.lastSampleTimeNs.value() < sensor.samplingPeriod.count()) { if (DEBUG_SENSOR_EVENT_DETAILS) { - ALOGD("Sensor %s Skip a sample.", NamedEnum::string(sensorType).c_str()); + ALOGD("Sensor %s Skip a sample.", ftl::enum_string(sensorType).c_str()); } } else { // Convert to Android unit diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index ac5f6b652b..419b0d0eed 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -18,9 +18,10 @@ #include "../Macros.h" // clang-format on -#include #include "TouchInputMapper.h" +#include + #include "CursorButtonAccumulator.h" #include "CursorScrollAccumulator.h" #include "TouchButtonAccumulator.h" @@ -259,7 +260,7 @@ void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { void TouchInputMapper::dump(std::string& dump) { dump += StringPrintf(INDENT2 "Touch Input Mapper (mode - %s):\n", - NamedEnum::string(mDeviceMode).c_str()); + ftl::enum_string(mDeviceMode).c_str()); dumpParameters(dump); dumpVirtualKeys(dump); dumpRawPointerAxes(dump); @@ -515,9 +516,9 @@ void TouchInputMapper::configureParameters() { void TouchInputMapper::dumpParameters(std::string& dump) { dump += INDENT3 "Parameters:\n"; - dump += INDENT4 "GestureMode: " + NamedEnum::string(mParameters.gestureMode) + "\n"; + dump += INDENT4 "GestureMode: " + ftl::enum_string(mParameters.gestureMode) + "\n"; - dump += INDENT4 "DeviceType: " + NamedEnum::string(mParameters.deviceType) + "\n"; + dump += INDENT4 "DeviceType: " + ftl::enum_string(mParameters.deviceType) + "\n"; dump += StringPrintf(INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s, " "displayId='%s'\n", @@ -525,7 +526,7 @@ void TouchInputMapper::dumpParameters(std::string& dump) { toString(mParameters.associatedDisplayIsExternal), mParameters.uniqueDisplayId.c_str()); dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); - dump += INDENT4 "Orientation: " + NamedEnum::string(mParameters.orientation) + "\n"; + dump += INDENT4 "Orientation: " + ftl::enum_string(mParameters.orientation) + "\n"; } void TouchInputMapper::configureRawPointerAxes() { diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index e104220e47..a56468f445 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -185,6 +185,8 @@ protected: UNSCALED, // unscaled mapping (touchpad) NAVIGATION, // unscaled mapping with assist gesture (touch navigation) POINTER, // pointer mapping (pointer) + + ftl_last = POINTER }; DeviceMode mDeviceMode; @@ -198,6 +200,8 @@ protected: TOUCH_PAD, TOUCH_NAVIGATION, POINTER, + + ftl_last = POINTER }; DeviceType deviceType; @@ -210,6 +214,8 @@ protected: ORIENTATION_90 = DISPLAY_ORIENTATION_90, ORIENTATION_180 = DISPLAY_ORIENTATION_180, ORIENTATION_270 = DISPLAY_ORIENTATION_270, + + ftl_last = ORIENTATION_270 }; Orientation orientation; @@ -219,6 +225,8 @@ protected: enum class GestureMode { SINGLE_TOUCH, MULTI_TOUCH, + + ftl_last = MULTI_TOUCH }; GestureMode gestureMode; @@ -818,4 +826,4 @@ private: } // namespace android -#endif // _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H \ No newline at end of file +#endif // _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp index f310738423..1ef8f78894 100644 --- a/services/surfaceflinger/ClientCache.cpp +++ b/services/surfaceflinger/ClientCache.cpp @@ -21,12 +21,12 @@ #include +#include + #include "ClientCache.h" namespace android { -using base::StringAppendF; - ANDROID_SINGLETON_STATIC_INSTANCE(ClientCache); ClientCache::ClientCache() : mDeathRecipient(new CacheDeathRecipient) {} @@ -212,16 +212,15 @@ void ClientCache::CacheDeathRecipient::binderDied(const wp& who) { void ClientCache::dump(std::string& result) { std::lock_guard lock(mMutex); - for (auto i : mBuffers) { - const sp& cacheOwner = i.second.first; - StringAppendF(&result," Cache owner: %p\n", cacheOwner.get()); - auto &buffers = i.second.second; - for (auto& [id, clientCacheBuffer] : buffers) { - StringAppendF(&result, "\t ID: %d, Width/Height: %d,%d\n", (int)id, - (int)clientCacheBuffer.buffer->getBuffer()->getWidth(), - (int)clientCacheBuffer.buffer->getBuffer()->getHeight()); + for (const auto& [_, cache] : mBuffers) { + base::StringAppendF(&result, " Cache owner: %p\n", cache.first.get()); + + for (const auto& [id, entry] : cache.second) { + const auto& buffer = entry.buffer->getBuffer(); + base::StringAppendF(&result, "\tID: %" PRIu64 ", size: %ux%u\n", id, buffer->getWidth(), + buffer->getHeight()); } } } -}; // namespace android +} // namespace android diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp index 936dba3b29..2532e3df5d 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp @@ -93,11 +93,7 @@ Flags LayerState::getDifferingFields(const LayerState& other) c void LayerState::dump(std::string& result) const { for (const StateInterface* field : getNonUniqueFields()) { - if (auto viewOpt = flag_name(field->getField()); viewOpt) { - base::StringAppendF(&result, " %16s: ", std::string(*viewOpt).c_str()); - } else { - result.append(":\n"); - } + base::StringAppendF(&result, " %16s: ", ftl::flag_string(field->getField()).c_str()); bool first = true; for (const std::string& line : field->toStrings()) { @@ -126,11 +122,7 @@ std::optional LayerState::compare(const LayerState& other) const { continue; } - if (auto viewOpt = flag_name(thisField->getField()); viewOpt) { - base::StringAppendF(&result, " %16s: ", std::string(*viewOpt).c_str()); - } else { - result.append(":\n"); - } + base::StringAppendF(&result, " %16s: ", ftl::flag_string(thisField->getField()).c_str()); const auto& thisStrings = thisField->toStrings(); const auto& otherStrings = otherField->toStrings(); -- cgit v1.2.3-59-g8ed1b From edb375df82f6b48688d85c11dbca91adef088bc8 Mon Sep 17 00:00:00 2001 From: Robin Lee Date: Fri, 10 Sep 2021 12:03:42 +0000 Subject: Initialize DrawingState::trustedOverlay to false in constructor To avoid it being initialised to true randomly. Bug: 199483370 Change-Id: I75be2b1d305e22f8a71532b9f5b8ea6c469baaaa --- services/surfaceflinger/Layer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 804cf9a3a0..f070d8704c 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -134,6 +134,7 @@ Layer::Layer(const LayerCreationArgs& args) mDrawingState.frameTimelineInfo = {}; mDrawingState.postTime = -1; mDrawingState.destinationFrame.makeInvalid(); + mDrawingState.isTrustedOverlay = false; if (args.flags & ISurfaceComposerClient::eNoColorFill) { // Set an invalid color so there is no color fill. -- cgit v1.2.3-59-g8ed1b From 2a0066dad5412c5135338988b2b88061818b7962 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 15 Jul 2021 20:16:58 -0700 Subject: SF: return the active display from getInternalDisplayId So clients that uses SurfaceComposerClient::getInternalDisplayId such as screenrecord would get the current active display Test: screenrecord Bug: 193821864 Bug: 199336728 Change-Id: Ief856c736c78ab9ddca3c4ffccd8e374c050b0bd --- services/surfaceflinger/SurfaceFlinger.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d70e2e979b..34b5cdc3fe 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -619,12 +619,18 @@ void SurfaceFlinger::releaseVirtualDisplay(VirtualDisplayId displayId) { std::vector SurfaceFlinger::getPhysicalDisplayIdsLocked() const { std::vector displayIds; displayIds.reserve(mPhysicalDisplayTokens.size()); + const auto defaultDisplayId = [this]() REQUIRES(mStateLock) { + if (const auto display = getDefaultDisplayDeviceLocked()) { + return display->getPhysicalId(); + } - const auto internalDisplayId = getInternalDisplayIdLocked(); - displayIds.push_back(internalDisplayId); + // fallback to the internal display id if the active display is unknown + return getInternalDisplayIdLocked(); + }(); + displayIds.push_back(defaultDisplayId); for (const auto& [id, token] : mPhysicalDisplayTokens) { - if (id != internalDisplayId) { + if (id != defaultDisplayId) { displayIds.push_back(id); } } -- cgit v1.2.3-59-g8ed1b From 12aaf8e35911cd5f036917de9a6f388d611ed51c Mon Sep 17 00:00:00 2001 From: Dmitri Plotnikov Date: Fri, 3 Sep 2021 19:07:23 -0700 Subject: Simplify initialization and add setValue to support parceling Bug: 197162116 Test: atest libbattery_test Change-Id: I4278206eab049d714c5278e6b10ba3155e17142f --- libs/battery/LongArrayMultiStateCounter.cpp | 2 +- libs/battery/LongArrayMultiStateCounterTest.cpp | 19 ++++- libs/battery/MultiStateCounter.h | 107 +++++++++++++++--------- libs/battery/MultiStateCounterTest.cpp | 35 ++++++-- 4 files changed, 116 insertions(+), 47 deletions(-) diff --git a/libs/battery/LongArrayMultiStateCounter.cpp b/libs/battery/LongArrayMultiStateCounter.cpp index 68e088394a..125cfaffa4 100644 --- a/libs/battery/LongArrayMultiStateCounter.cpp +++ b/libs/battery/LongArrayMultiStateCounter.cpp @@ -62,7 +62,7 @@ void LongArrayMultiStateCounter::add(std::vector* value1, template <> std::string LongArrayMultiStateCounter::valueToString(const std::vector& v) const { std::stringstream s; - s << "{ "; + s << "{"; bool first = true; for (uint64_t n : v) { if (!first) { diff --git a/libs/battery/LongArrayMultiStateCounterTest.cpp b/libs/battery/LongArrayMultiStateCounterTest.cpp index 24cb437eaa..e4e6b2a49f 100644 --- a/libs/battery/LongArrayMultiStateCounterTest.cpp +++ b/libs/battery/LongArrayMultiStateCounterTest.cpp @@ -24,7 +24,9 @@ namespace battery { class LongArrayMultiStateCounterTest : public testing::Test {}; TEST_F(LongArrayMultiStateCounterTest, stateChange) { - LongArrayMultiStateCounter testCounter(2, 0, std::vector(4), 1000); + LongArrayMultiStateCounter testCounter(2, std::vector(4)); + testCounter.updateValue(std::vector({0, 0, 0, 0}), 1000); + testCounter.setState(0, 1000); testCounter.setState(1, 2000); testCounter.updateValue(std::vector({100, 200, 300, 400}), 3000); @@ -34,7 +36,9 @@ TEST_F(LongArrayMultiStateCounterTest, stateChange) { } TEST_F(LongArrayMultiStateCounterTest, accumulation) { - LongArrayMultiStateCounter testCounter(2, 0, std::vector(4), 1000); + LongArrayMultiStateCounter testCounter(2, std::vector(4)); + testCounter.updateValue(std::vector({0, 0, 0, 0}), 1000); + testCounter.setState(0, 1000); testCounter.setState(1, 2000); testCounter.updateValue(std::vector({100, 200, 300, 400}), 3000); testCounter.setState(0, 4000); @@ -50,5 +54,16 @@ TEST_F(LongArrayMultiStateCounterTest, accumulation) { EXPECT_EQ(std::vector({70, 120, 170, 220}), testCounter.getCount(1)); } +TEST_F(LongArrayMultiStateCounterTest, toString) { + LongArrayMultiStateCounter testCounter(2, std::vector(4)); + testCounter.updateValue(std::vector({0, 0, 0, 0}), 1000); + testCounter.setState(0, 1000); + testCounter.setState(1, 2000); + testCounter.updateValue(std::vector({100, 200, 300, 400}), 3000); + + EXPECT_STREQ("[0: {50, 100, 150, 200}, 1: {50, 100, 150, 200}] updated: 3000 currentState: 1", + testCounter.toString().c_str()); +} + } // namespace battery } // namespace android diff --git a/libs/battery/MultiStateCounter.h b/libs/battery/MultiStateCounter.h index 9f56b29dfb..40de068a95 100644 --- a/libs/battery/MultiStateCounter.h +++ b/libs/battery/MultiStateCounter.h @@ -51,15 +51,18 @@ class MultiStateCounter { State* states; public: - MultiStateCounter(uint16_t stateCount, state_t initialState, const T& emptyValue, - time_t timestamp); + MultiStateCounter(uint16_t stateCount, const T& emptyValue); virtual ~MultiStateCounter(); void setState(state_t state, time_t timestamp); + void setValue(state_t state, const T& value); + void updateValue(const T& value, time_t timestamp); + uint16_t getStateCount(); + const T& getCount(state_t state); std::string toString(); @@ -86,14 +89,13 @@ private: // Since MultiStateCounter is a template, the implementation must be inlined. template -MultiStateCounter::MultiStateCounter(uint16_t stateCount, state_t initialState, - const T& emptyValue, time_t timestamp) +MultiStateCounter::MultiStateCounter(uint16_t stateCount, const T& emptyValue) : stateCount(stateCount), - currentState(initialState), - lastStateChangeTimestamp(timestamp), + currentState(0), + lastStateChangeTimestamp(-1), emptyValue(emptyValue), lastValue(emptyValue), - lastUpdateTimestamp(timestamp), + lastUpdateTimestamp(-1), deltaValue(emptyValue) { states = new State[stateCount]; for (int i = 0; i < stateCount; i++) { @@ -109,53 +111,68 @@ MultiStateCounter::~MultiStateCounter() { template void MultiStateCounter::setState(state_t state, time_t timestamp) { - if (timestamp >= lastStateChangeTimestamp) { - states[currentState].timeInStateSinceUpdate += timestamp - lastStateChangeTimestamp; - } else { - ALOGE("setState is called with an earlier timestamp: %lu, previous timestamp: %lu\n", - (unsigned long)timestamp, (unsigned long)lastStateChangeTimestamp); - // The accumulated durations have become unreliable. For example, if the timestamp - // sequence was 1000, 2000, 1000, 3000, if we accumulated the positive deltas, - // we would get 4000, which is greater than (last - first). This could lead to - // counts exceeding 100%. - for (int i = 0; i < stateCount; i++) { - states[i].timeInStateSinceUpdate = 0; + if (lastStateChangeTimestamp >= 0) { + if (timestamp >= lastStateChangeTimestamp) { + states[currentState].timeInStateSinceUpdate += timestamp - lastStateChangeTimestamp; + } else { + ALOGE("setState is called with an earlier timestamp: %lu, previous timestamp: %lu\n", + (unsigned long)timestamp, (unsigned long)lastStateChangeTimestamp); + // The accumulated durations have become unreliable. For example, if the timestamp + // sequence was 1000, 2000, 1000, 3000, if we accumulated the positive deltas, + // we would get 4000, which is greater than (last - first). This could lead to + // counts exceeding 100%. + for (int i = 0; i < stateCount; i++) { + states[i].timeInStateSinceUpdate = 0; + } } } currentState = state; lastStateChangeTimestamp = timestamp; } +template +void MultiStateCounter::setValue(state_t state, const T& value) { + states[state].counter = value; +} + template void MultiStateCounter::updateValue(const T& value, time_t timestamp) { // Confirm the current state for the side-effect of updating the time-in-state // counter for the current state. setState(currentState, timestamp); - if (timestamp > lastUpdateTimestamp) { - if (delta(lastValue, value, &deltaValue)) { - time_t timeSinceUpdate = timestamp - lastUpdateTimestamp; - for (int i = 0; i < stateCount; i++) { - time_t timeInState = states[i].timeInStateSinceUpdate; - if (timeInState) { - add(&states[i].counter, deltaValue, timeInState, timeSinceUpdate); - states[i].timeInStateSinceUpdate = 0; + if (lastUpdateTimestamp >= 0) { + if (timestamp > lastUpdateTimestamp) { + if (delta(lastValue, value, &deltaValue)) { + time_t timeSinceUpdate = timestamp - lastUpdateTimestamp; + for (int i = 0; i < stateCount; i++) { + time_t timeInState = states[i].timeInStateSinceUpdate; + if (timeInState) { + add(&states[i].counter, deltaValue, timeInState, timeSinceUpdate); + states[i].timeInStateSinceUpdate = 0; + } } + } else { + std::stringstream str; + str << "updateValue is called with a value " << valueToString(value) + << ", which is lower than the previous value " << valueToString(lastValue) + << "\n"; + ALOGE("%s", str.str().c_str()); } - } else { - std::stringstream str; - str << "updateValue is called with a value " << valueToString(value) - << ", which is lower than the previous value " << valueToString(lastValue) << "\n"; - ALOGE("%s", str.str().c_str()); + } else if (timestamp < lastUpdateTimestamp) { + ALOGE("updateValue is called with an earlier timestamp: %lu, previous timestamp: %lu\n", + (unsigned long)timestamp, (unsigned long)lastUpdateTimestamp); } - } else if (timestamp < lastUpdateTimestamp) { - ALOGE("updateValue is called with an earlier timestamp: %lu, previous timestamp: %lu\n", - (unsigned long)timestamp, (unsigned long)lastUpdateTimestamp); } lastValue = value; lastUpdateTimestamp = timestamp; } +template +uint16_t MultiStateCounter::getStateCount() { + return stateCount; +} + template const T& MultiStateCounter::getCount(state_t state) { return states[state].counter; @@ -164,17 +181,29 @@ const T& MultiStateCounter::getCount(state_t state) { template std::string MultiStateCounter::toString() { std::stringstream str; - str << "currentState: " << currentState - << " lastStateChangeTimestamp: " << lastStateChangeTimestamp - << " lastUpdateTimestamp: " << lastUpdateTimestamp << " states: ["; + str << "["; for (int i = 0; i < stateCount; i++) { if (i != 0) { str << ", "; } - str << i << ": time: " << states[i].timeInStateSinceUpdate - << " counter: " << valueToString(states[i].counter); + str << i << ": " << valueToString(states[i].counter); + if (states[i].timeInStateSinceUpdate > 0) { + str << " timeInStateSinceUpdate: " << states[i].timeInStateSinceUpdate; + } } str << "]"; + if (lastUpdateTimestamp >= 0) { + str << " updated: " << lastUpdateTimestamp; + } + if (lastStateChangeTimestamp >= 0) { + str << " currentState: " << currentState; + if (lastStateChangeTimestamp > lastUpdateTimestamp) { + str << " stateChanged: " << lastStateChangeTimestamp; + } + } else { + str << " currentState: none"; + } + return str.str(); } diff --git a/libs/battery/MultiStateCounterTest.cpp b/libs/battery/MultiStateCounterTest.cpp index 942d5cadf5..87c80c53d3 100644 --- a/libs/battery/MultiStateCounterTest.cpp +++ b/libs/battery/MultiStateCounterTest.cpp @@ -49,8 +49,9 @@ std::string DoubleMultiStateCounter::valueToString(const double& v) const { class MultiStateCounterTest : public testing::Test {}; TEST_F(MultiStateCounterTest, constructor) { - DoubleMultiStateCounter testCounter(3, 1, 0, 1000); - testCounter.setState(1, 2000); + DoubleMultiStateCounter testCounter(3, 0); + testCounter.updateValue(0, 0); + testCounter.setState(1, 0); testCounter.updateValue(3.14, 3000); EXPECT_DOUBLE_EQ(0, testCounter.getCount(0)); @@ -59,7 +60,9 @@ TEST_F(MultiStateCounterTest, constructor) { } TEST_F(MultiStateCounterTest, stateChange) { - DoubleMultiStateCounter testCounter(3, 1, 0, 0); + DoubleMultiStateCounter testCounter(3, 0); + testCounter.updateValue(0, 0); + testCounter.setState(1, 0); testCounter.setState(2, 1000); testCounter.updateValue(6.0, 3000); @@ -69,7 +72,9 @@ TEST_F(MultiStateCounterTest, stateChange) { } TEST_F(MultiStateCounterTest, timeAdjustment_setState) { - DoubleMultiStateCounter testCounter(3, 1, 0, 0); + DoubleMultiStateCounter testCounter(3, 0); + testCounter.updateValue(0, 0); + testCounter.setState(1, 0); testCounter.setState(2, 2000); // Time moves back @@ -88,7 +93,9 @@ TEST_F(MultiStateCounterTest, timeAdjustment_setState) { } TEST_F(MultiStateCounterTest, timeAdjustment_updateValue) { - DoubleMultiStateCounter testCounter(1, 0, 0, 0); + DoubleMultiStateCounter testCounter(1, 0); + testCounter.updateValue(0, 0); + testCounter.setState(0, 0); testCounter.updateValue(6.0, 2000); // Time moves back. The negative delta from 2000 to 1000 is ignored @@ -101,5 +108,23 @@ TEST_F(MultiStateCounterTest, timeAdjustment_updateValue) { EXPECT_DOUBLE_EQ(9.0, testCounter.getCount(0)); } +TEST_F(MultiStateCounterTest, toString) { + DoubleMultiStateCounter testCounter(2, 0); + + EXPECT_STREQ("[0: 0.000000, 1: 0.000000] currentState: none", testCounter.toString().c_str()); + + testCounter.updateValue(0, 0); + testCounter.setState(1, 0); + testCounter.setState(1, 2000); + EXPECT_STREQ("[0: 0.000000, 1: 0.000000 timeInStateSinceUpdate: 2000]" + " updated: 0 currentState: 1 stateChanged: 2000", + testCounter.toString().c_str()); + + testCounter.updateValue(3.14, 3000); + + EXPECT_STREQ("[0: 0.000000, 1: 3.140000] updated: 3000 currentState: 1", + testCounter.toString().c_str()); +} + } // namespace battery } // namespace android -- cgit v1.2.3-59-g8ed1b From ca20550407a1707c48f4c3a839ef55725962f19c Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 16 Jul 2021 21:31:58 +0000 Subject: Cancel wallpaper touch stream when foreground window is gone When the foreground window is gone, we should also cancel the touch stream for its wallpaper window. We already cancel touch for the window itself, and for global monitor. Without this patch, the wallpaper window simply stops receiving touches, and never gets CANCEL, either. The behaviour is slightly strange for the global monitor in this case. First of all, the global monitor receives CANCEL, which is questionable (things like pointer location stop working). Also, it only gets cancel when a *new* event comes in. That said, it's probably fine, so let's just document this behaviour by adding a test for it. Bug: 192981537 Test: atest inputflinger_tests Change-Id: I8a2ef7cd552acc5cf64b2e13a6df5d5988bd1808 --- include/input/Input.h | 12 +- libs/input/Input.cpp | 4 +- .../inputflinger/dispatcher/InputDispatcher.cpp | 20 +- services/inputflinger/dispatcher/TouchState.cpp | 10 + services/inputflinger/dispatcher/TouchState.h | 1 + .../inputflinger/tests/InputDispatcher_test.cpp | 267 ++++++++++++++++++++- 6 files changed, 302 insertions(+), 12 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index d2d9fd48e8..f170f0fa23 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -524,13 +524,17 @@ public: inline int32_t getAction() const { return mAction; } - inline int32_t getActionMasked() const { return mAction & AMOTION_EVENT_ACTION_MASK; } + static int32_t getActionMasked(int32_t action) { return action & AMOTION_EVENT_ACTION_MASK; } - inline int32_t getActionIndex() const { - return (mAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) - >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + inline int32_t getActionMasked() const { return getActionMasked(mAction); } + + static int32_t getActionIndex(int32_t action) { + return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> + AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } + inline int32_t getActionIndex() const { return getActionIndex(mAction); } + inline void setAction(int32_t action) { mAction = action; } inline int32_t getFlags() const { return mFlags; } diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 1e8ff945ef..037849eac4 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -834,9 +834,9 @@ std::string MotionEvent::actionToString(int32_t action) { case AMOTION_EVENT_ACTION_OUTSIDE: return "OUTSIDE"; case AMOTION_EVENT_ACTION_POINTER_DOWN: - return "POINTER_DOWN"; + return StringPrintf("POINTER_DOWN(%" PRId32 ")", MotionEvent::getActionIndex(action)); case AMOTION_EVENT_ACTION_POINTER_UP: - return "POINTER_UP"; + return StringPrintf("POINTER_UP(%" PRId32 ")", MotionEvent::getActionIndex(action)); case AMOTION_EVENT_ACTION_HOVER_MOVE: return "HOVER_MOVE"; case AMOTION_EVENT_ACTION_SCROLL: diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 058e099faa..ce383d9f25 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -1706,13 +1706,13 @@ void InputDispatcher::logOutboundMotionDetails(const char* prefix, const MotionE if (DEBUG_OUTBOUND_EVENT_DETAILS) { ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 ", policyFlags=0x%x, " - "action=0x%x, actionButton=0x%x, flags=0x%x, " + "action=%s, actionButton=0x%x, flags=0x%x, " "metaState=0x%x, buttonState=0x%x," "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64, prefix, entry.eventTime, entry.deviceId, entry.source, entry.displayId, - entry.policyFlags, entry.action, entry.actionButton, entry.flags, entry.metaState, - entry.buttonState, entry.edgeFlags, entry.xPrecision, entry.yPrecision, - entry.downTime); + entry.policyFlags, MotionEvent::actionToString(entry.action).c_str(), + entry.actionButton, entry.flags, entry.metaState, entry.buttonState, entry.edgeFlags, + entry.xPrecision, entry.yPrecision, entry.downTime); for (uint32_t i = 0; i < entry.pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%d, " @@ -4642,6 +4642,18 @@ void InputDispatcher::setInputWindowsLocked( CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, "touched window was removed"); synthesizeCancelationEventsForInputChannelLocked(touchedInputChannel, options); + // Since we are about to drop the touch, cancel the events for the wallpaper as + // well. + if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND && + touchedWindow.windowHandle->getInfo()->hasWallpaper) { + sp wallpaper = state.getWallpaperWindow(); + if (wallpaper != nullptr) { + sp wallpaperConnection = + getConnectionLocked(wallpaper->getToken()); + synthesizeCancelationEventsForConnectionLocked(wallpaperConnection, + options); + } + } } state.windows.erase(state.windows.begin() + i); } else { diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index b7ed658777..4a50a683e9 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -134,4 +134,14 @@ bool TouchState::isSlippery() const { return haveSlipperyForegroundWindow; } +sp TouchState::getWallpaperWindow() const { + for (size_t i = 0; i < windows.size(); i++) { + const TouchedWindow& window = windows[i]; + if (window.windowHandle->getInfo()->type == WindowInfo::Type::WALLPAPER) { + return window.windowHandle; + } + } + return nullptr; +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index 579b868443..7dcf55d813 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -51,6 +51,7 @@ struct TouchState { void filterNonMonitors(); sp getFirstForegroundWindowHandle() const; bool isSlippery() const; + sp getWallpaperWindow() const; }; } // namespace inputdispatcher diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 0a91bde03b..e223372fe1 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -74,6 +74,12 @@ static KeyEvent getTestKeyEvent() { return event; } +static void assertMotionAction(int32_t expectedAction, int32_t receivedAction) { + ASSERT_EQ(expectedAction, receivedAction) + << "expected " << MotionEvent::actionToString(expectedAction) << ", got " + << MotionEvent::actionToString(receivedAction); +} + // --- FakeInputDispatcherPolicy --- class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { @@ -801,7 +807,8 @@ public: } case AINPUT_EVENT_TYPE_MOTION: { const MotionEvent& motionEvent = static_cast(*event); - EXPECT_EQ(expectedAction, motionEvent.getAction()); + assertMotionAction(expectedAction, motionEvent.getAction()); + if (expectedFlags.has_value()) { EXPECT_EQ(expectedFlags.value(), motionEvent.getFlags()); } @@ -982,6 +989,10 @@ public: mInfo.addTouchableRegion(frame); } + void setType(WindowInfo::Type type) { mInfo.type = type; } + + void setHasWallpaper(bool hasWallpaper) { mInfo.hasWallpaper = hasWallpaper; } + void addFlags(Flags flags) { mInfo.flags |= flags; } void setFlags(Flags flags) { mInfo.flags = flags; } @@ -1485,6 +1496,197 @@ TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) { windowSecond->assertNoEvents(); } +/** + * Two windows: A top window, and a wallpaper behind the window. + * Touch goes to the top window, and then top window disappears. Ensure that wallpaper window + * gets ACTION_CANCEL. + * 1. foregroundWindow <-- has wallpaper (hasWallpaper=true) + * 2. wallpaperWindow <-- is wallpaper (type=InputWindowInfo::Type::WALLPAPER) + */ +TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) { + std::shared_ptr application = std::make_shared(); + sp foregroundWindow = + new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); + foregroundWindow->setHasWallpaper(true); + sp wallpaperWindow = + new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); + wallpaperWindow->setType(WindowInfo::Type::WALLPAPER); + constexpr int expectedWallpaperFlags = + AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}}); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 200})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + // Both foreground window and its wallpaper should receive the touch down + foregroundWindow->consumeMotionDown(); + wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {110, 200})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + foregroundWindow->consumeMotionMove(); + wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + + // Now the foreground window goes away, but the wallpaper stays + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wallpaperWindow}}}); + foregroundWindow->consumeMotionCancel(); + // Since the "parent" window of the wallpaper is gone, wallpaper should receive cancel, too. + wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); +} + +/** + * A single window that receives touch (on top), and a wallpaper window underneath it. + * The top window gets a multitouch gesture. + * Ensure that wallpaper gets the same gesture. + */ +TEST_F(InputDispatcherTest, WallpaperWindow_ReceivesMultiTouch) { + std::shared_ptr application = std::make_shared(); + sp window = + new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); + window->setHasWallpaper(true); + + sp wallpaperWindow = + new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); + wallpaperWindow->setType(WindowInfo::Type::WALLPAPER); + constexpr int expectedWallpaperFlags = + AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, wallpaperWindow}}}); + + // Touch down on top window + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 100})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + // Both top window and its wallpaper should receive the touch down + window->consumeMotionDown(); + wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + + // Second finger down on the top window + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(100) + .y(100)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(150) + .y(150)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + window->consumeMotionPointerDown(1 /* pointerIndex */); + wallpaperWindow->consumeMotionPointerDown(1 /* pointerIndex */, ADISPLAY_ID_DEFAULT, + expectedWallpaperFlags); + window->assertNoEvents(); + wallpaperWindow->assertNoEvents(); +} + +/** + * Two windows: a window on the left and window on the right. + * A third window, wallpaper, is behind both windows, and spans both top windows. + * The first touch down goes to the left window. A second pointer touches down on the right window. + * The touch is split, so both left and right windows should receive ACTION_DOWN. + * The wallpaper will get the full event, so it should receive ACTION_DOWN followed by + * ACTION_POINTER_DOWN(1). + */ +TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { + std::shared_ptr application = std::make_shared(); + sp leftWindow = + new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); + leftWindow->setFrame(Rect(0, 0, 200, 200)); + leftWindow->setFlags(WindowInfo::Flag::SPLIT_TOUCH | WindowInfo::Flag::NOT_TOUCH_MODAL); + leftWindow->setHasWallpaper(true); + + sp rightWindow = + new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); + rightWindow->setFrame(Rect(200, 0, 400, 200)); + rightWindow->setFlags(WindowInfo::Flag::SPLIT_TOUCH | WindowInfo::Flag::NOT_TOUCH_MODAL); + rightWindow->setHasWallpaper(true); + + sp wallpaperWindow = + new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); + wallpaperWindow->setFrame(Rect(0, 0, 400, 200)); + wallpaperWindow->setType(WindowInfo::Type::WALLPAPER); + constexpr int expectedWallpaperFlags = + AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + + mDispatcher->setInputWindows( + {{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow, wallpaperWindow}}}); + + // Touch down on left window + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 100})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + // Both foreground window and its wallpaper should receive the touch down + leftWindow->consumeMotionDown(); + wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + + // Second finger down on the right window + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(100) + .y(100)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(300) + .y(100)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + leftWindow->consumeMotionMove(); + // Since the touch is split, right window gets ACTION_DOWN + rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); + wallpaperWindow->consumeMotionPointerDown(1 /* pointerIndex */, ADISPLAY_ID_DEFAULT, + expectedWallpaperFlags); + + // Now, leftWindow, which received the first finger, disappears. + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {rightWindow, wallpaperWindow}}}); + leftWindow->consumeMotionCancel(); + // Since a "parent" window of the wallpaper is gone, wallpaper should receive cancel, too. + wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + + // The pointer that's still down on the right window moves, and goes to the right window only. + // As far as the dispatcher's concerned though, both pointers are still present. + const MotionEvent secondFingerMoveEvent = + MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(100) + .y(100)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(310) + .y(110)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)); + rightWindow->consumeMotionMove(); + + leftWindow->assertNoEvents(); + rightWindow->assertNoEvents(); + wallpaperWindow->assertNoEvents(); +} + TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { std::shared_ptr application = std::make_shared(); sp windowLeft = @@ -2301,11 +2503,21 @@ public: expectedDisplayId, expectedFlags); } + void consumeMotionMove(int32_t expectedDisplayId, int32_t expectedFlags = 0) { + mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_MOVE, + expectedDisplayId, expectedFlags); + } + void consumeMotionUp(int32_t expectedDisplayId, int32_t expectedFlags = 0) { mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_UP, expectedDisplayId, expectedFlags); } + void consumeMotionCancel(int32_t expectedDisplayId, int32_t expectedFlags = 0) { + mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, + expectedDisplayId, expectedFlags); + } + MotionEvent* consumeMotion() { InputEvent* event = mInputReceiver->consume(); if (!event) { @@ -2325,6 +2537,57 @@ private: std::unique_ptr mInputReceiver; }; +/** + * Two entities that receive touch: A window, and a global monitor. + * The touch goes to the window, and then the window disappears. + * The monitor does not get cancel right away. But if more events come in, the touch gets canceled + * for the monitor, as well. + * 1. foregroundWindow + * 2. monitor <-- global monitor (doesn't observe z order, receives all events) + */ +TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_GlobalMonitorTouchIsCanceled) { + std::shared_ptr application = std::make_shared(); + sp window = + new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); + + FakeMonitorReceiver monitor = + FakeMonitorReceiver(mDispatcher, "GlobalMonitor", ADISPLAY_ID_DEFAULT, + false /*isGestureMonitor*/); + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 200})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + // Both the foreground window and the global monitor should receive the touch down + window->consumeMotionDown(); + monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {110, 200})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + window->consumeMotionMove(); + monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT); + + // Now the foreground window goes away + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {}}}); + window->consumeMotionCancel(); + monitor.assertNoEvents(); // Global monitor does not get a cancel yet + + // If more events come in, there will be no more foreground window to send them to. This will + // cause a cancel for the monitor, as well. + ASSERT_EQ(InputEventInjectionResult::FAILED, + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {120, 200})) + << "Injection should fail because the window was removed"; + window->assertNoEvents(); + // Global monitor now gets the cancel + monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT); +} + // Tests for gesture monitors TEST_F(InputDispatcherTest, GestureMonitor_ReceivesMotionEvents) { std::shared_ptr application = std::make_shared(); @@ -3567,7 +3830,7 @@ protected: << " event, got " << inputEventTypeToString(event->getType()) << " event"; const MotionEvent& motionEvent = static_cast(*event); - EXPECT_EQ(expectedAction, motionEvent.getAction()); + assertMotionAction(expectedAction, motionEvent.getAction()); for (size_t i = 0; i < points.size(); i++) { float expectedX = points[i].x; -- cgit v1.2.3-59-g8ed1b From 48f8cb998c61fcad3db9ca7bbebc9e424844e6e2 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 26 Aug 2021 14:05:36 -0700 Subject: Report gui::DisplayInfo to clients with window info changes InputFlinger needs to know specifications about displays such as orientation and projection from SurfaceFlinger to support the MotionEvent#getRaw API, which returns coordinates in logical display space at the moment. Since dispatcher gets window information from SF, we need to send the display information that affects input dispatching at the same time as updating window information to ensure those two pieces of information remain in sync. Instead of sending display information along with each window, we attempt to reduce the amount of information sent through binder by sending DisplayInfo separately to WindowInfos. The newly added DisplayInfo struct should only be used by InputFlinger to support raw coordinates for now, with the goal of removing it altogether in the future. Bug: 179274888 Test: atest libgui_test inputflinger_tests Test: manual, ensure input works Change-Id: I87429ca4ced5f105f49a117c676cba29f8a5c4da --- libs/gui/Android.bp | 8 ++- libs/gui/DisplayInfo.cpp | 70 ++++++++++++++++++++++ libs/gui/WindowInfo.cpp | 17 ++---- libs/gui/WindowInfosListenerReporter.cpp | 5 +- libs/gui/android/gui/DisplayInfo.aidl | 19 ++++++ libs/gui/android/gui/IWindowInfosListener.aidl | 3 +- libs/gui/include/gui/DisplayInfo.h | 46 ++++++++++++++ libs/gui/include/gui/WindowInfo.h | 7 --- libs/gui/include/gui/WindowInfosListener.h | 4 +- libs/gui/include/gui/WindowInfosListenerReporter.h | 4 +- libs/gui/tests/Android.bp | 7 ++- libs/gui/tests/DisplayInfo_test.cpp | 49 +++++++++++++++ libs/gui/tests/WindowInfo_test.cpp | 5 -- .../inputflinger/dispatcher/InputDispatcher.cpp | 52 ++++++++++++---- services/inputflinger/dispatcher/InputDispatcher.h | 7 ++- services/surfaceflinger/DisplayDevice.cpp | 28 +++++++++ services/surfaceflinger/DisplayDevice.h | 4 ++ services/surfaceflinger/Layer.cpp | 33 +--------- services/surfaceflinger/Layer.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 17 +++++- .../surfaceflinger/WindowInfosListenerInvoker.cpp | 4 +- .../surfaceflinger/WindowInfosListenerInvoker.h | 3 +- .../tests/WindowInfosListener_test.cpp | 4 +- 23 files changed, 311 insertions(+), 87 deletions(-) create mode 100644 libs/gui/DisplayInfo.cpp create mode 100644 libs/gui/android/gui/DisplayInfo.aidl create mode 100644 libs/gui/include/gui/DisplayInfo.h create mode 100644 libs/gui/tests/DisplayInfo_test.cpp diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 326da3a7b5..2d1f5a1694 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -65,11 +65,13 @@ cc_library_static { host_supported: true, srcs: [ ":guiconstants_aidl", + "android/gui/DisplayInfo.aidl", "android/gui/FocusRequest.aidl", "android/gui/InputApplicationInfo.aidl", "android/gui/IWindowInfosListener.aidl", "android/gui/IWindowInfosReportedListener.aidl", "android/gui/WindowInfo.aidl", + "DisplayInfo.cpp", "WindowInfo.cpp", ], @@ -90,7 +92,7 @@ cc_library_static { ], aidl: { - export_aidl_headers: true + export_aidl_headers: true, }, include_dirs: [ @@ -135,8 +137,8 @@ cc_library_static { ], aidl: { - export_aidl_headers: true - } + export_aidl_headers: true, + }, } cc_library_shared { diff --git a/libs/gui/DisplayInfo.cpp b/libs/gui/DisplayInfo.cpp new file mode 100644 index 0000000000..52d9540eeb --- /dev/null +++ b/libs/gui/DisplayInfo.cpp @@ -0,0 +1,70 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "DisplayInfo" + +#include +#include +#include + +#include + +namespace android::gui { + +// --- DisplayInfo --- + +status_t DisplayInfo::readFromParcel(const android::Parcel* parcel) { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + + float dsdx, dtdx, tx, dtdy, dsdy, ty; + SAFE_PARCEL(parcel->readInt32, &displayId); + SAFE_PARCEL(parcel->readInt32, &logicalWidth); + SAFE_PARCEL(parcel->readInt32, &logicalHeight); + SAFE_PARCEL(parcel->readFloat, &dsdx); + SAFE_PARCEL(parcel->readFloat, &dtdx); + SAFE_PARCEL(parcel->readFloat, &tx); + SAFE_PARCEL(parcel->readFloat, &dtdy); + SAFE_PARCEL(parcel->readFloat, &dsdy); + SAFE_PARCEL(parcel->readFloat, &ty); + + transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1}); + + return OK; +} + +status_t DisplayInfo::writeToParcel(android::Parcel* parcel) const { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + + SAFE_PARCEL(parcel->writeInt32, displayId); + SAFE_PARCEL(parcel->writeInt32, logicalWidth); + SAFE_PARCEL(parcel->writeInt32, logicalHeight); + SAFE_PARCEL(parcel->writeFloat, transform.dsdx()); + SAFE_PARCEL(parcel->writeFloat, transform.dtdx()); + SAFE_PARCEL(parcel->writeFloat, transform.tx()); + SAFE_PARCEL(parcel->writeFloat, transform.dtdy()); + SAFE_PARCEL(parcel->writeFloat, transform.dsdy()); + SAFE_PARCEL(parcel->writeFloat, transform.ty()); + + return OK; +} + +} // namespace android::gui diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index b2ef7aabc9..5f3a726336 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -54,12 +54,11 @@ bool WindowInfo::operator==(const WindowInfo& info) const { info.frameLeft == frameLeft && info.frameTop == frameTop && info.frameRight == frameRight && info.frameBottom == frameBottom && info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor && - info.transform == transform && info.displayOrientation == displayOrientation && - info.displayWidth == displayWidth && info.displayHeight == displayHeight && - info.touchableRegion.hasSameRects(touchableRegion) && info.visible == visible && - info.trustedOverlay == trustedOverlay && info.focusable == focusable && - info.touchOcclusionMode == touchOcclusionMode && info.hasWallpaper == hasWallpaper && - info.paused == paused && info.ownerPid == ownerPid && info.ownerUid == ownerUid && + info.transform == transform && info.touchableRegion.hasSameRects(touchableRegion) && + info.visible == visible && info.trustedOverlay == trustedOverlay && + info.focusable == focusable && info.touchOcclusionMode == touchOcclusionMode && + info.hasWallpaper == hasWallpaper && info.paused == paused && + info.ownerPid == ownerPid && info.ownerUid == ownerUid && info.packageName == packageName && info.inputFeatures == inputFeatures && info.displayId == displayId && info.portalToDisplayId == portalToDisplayId && info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop && @@ -97,9 +96,6 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->writeFloat(transform.dtdy()) ?: parcel->writeFloat(transform.dsdy()) ?: parcel->writeFloat(transform.ty()) ?: - parcel->writeUint32(displayOrientation) ?: - parcel->writeInt32(displayWidth) ?: - parcel->writeInt32(displayHeight) ?: parcel->writeBool(visible) ?: parcel->writeBool(focusable) ?: parcel->writeBool(hasWallpaper) ?: @@ -155,9 +151,6 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { parcel->readFloat(&dtdy) ?: parcel->readFloat(&dsdy) ?: parcel->readFloat(&ty) ?: - parcel->readUint32(&displayOrientation) ?: - parcel->readInt32(&displayWidth) ?: - parcel->readInt32(&displayHeight) ?: parcel->readBool(&visible) ?: parcel->readBool(&focusable) ?: parcel->readBool(&hasWallpaper) ?: diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp index c00a4389ad..c32b9ab398 100644 --- a/libs/gui/WindowInfosListenerReporter.cpp +++ b/libs/gui/WindowInfosListenerReporter.cpp @@ -19,6 +19,7 @@ namespace android { +using gui::DisplayInfo; using gui::IWindowInfosReportedListener; using gui::WindowInfo; using gui::WindowInfosListener; @@ -65,7 +66,7 @@ status_t WindowInfosListenerReporter::removeWindowInfosListener( } binder::Status WindowInfosListenerReporter::onWindowInfosChanged( - const std::vector& windowInfos, + const std::vector& windowInfos, const std::vector& displayInfos, const sp& windowInfosReportedListener) { std::unordered_set, ISurfaceComposer::SpHash> windowInfosListeners; @@ -78,7 +79,7 @@ binder::Status WindowInfosListenerReporter::onWindowInfosChanged( } for (auto listener : windowInfosListeners) { - listener->onWindowInfosChanged(windowInfos); + listener->onWindowInfosChanged(windowInfos, displayInfos); } if (windowInfosReportedListener) { diff --git a/libs/gui/android/gui/DisplayInfo.aidl b/libs/gui/android/gui/DisplayInfo.aidl new file mode 100644 index 0000000000..30c088525d --- /dev/null +++ b/libs/gui/android/gui/DisplayInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2021, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.gui; + +parcelable DisplayInfo cpp_header "gui/DisplayInfo.h"; diff --git a/libs/gui/android/gui/IWindowInfosListener.aidl b/libs/gui/android/gui/IWindowInfosListener.aidl index d4553ca82d..a5b2762318 100644 --- a/libs/gui/android/gui/IWindowInfosListener.aidl +++ b/libs/gui/android/gui/IWindowInfosListener.aidl @@ -16,11 +16,12 @@ package android.gui; +import android.gui.DisplayInfo; import android.gui.IWindowInfosReportedListener; import android.gui.WindowInfo; /** @hide */ oneway interface IWindowInfosListener { - void onWindowInfosChanged(in WindowInfo[] windowInfos, in @nullable IWindowInfosReportedListener windowInfosReportedListener); + void onWindowInfosChanged(in WindowInfo[] windowInfos, in DisplayInfo[] displayInfos, in @nullable IWindowInfosReportedListener windowInfosReportedListener); } diff --git a/libs/gui/include/gui/DisplayInfo.h b/libs/gui/include/gui/DisplayInfo.h new file mode 100644 index 0000000000..74f33a2a87 --- /dev/null +++ b/libs/gui/include/gui/DisplayInfo.h @@ -0,0 +1,46 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +namespace android::gui { + +/* + * Describes information about a display that can have windows in it. + * + * This should only be used by InputFlinger to support raw coordinates in logical display space. + */ +struct DisplayInfo : public Parcelable { + int32_t displayId = ADISPLAY_ID_NONE; + + // Logical display dimensions. + int32_t logicalWidth = 0; + int32_t logicalHeight = 0; + + // The display transform. This takes display coordinates to logical display coordinates. + ui::Transform transform; + + status_t writeToParcel(android::Parcel*) const override; + + status_t readFromParcel(const android::Parcel*) override; +}; + +} // namespace android::gui \ No newline at end of file diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index f090c63228..7b7c923a58 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -168,13 +168,6 @@ struct WindowInfo : public Parcelable { // Transform applied to individual windows. ui::Transform transform; - // Display orientation as ui::Transform::RotationFlags. Used for compatibility raw coordinates. - uint32_t displayOrientation = ui::Transform::ROT_0; - - // Display size in its natural rotation. Used to rotate raw coordinates for compatibility. - int32_t displayWidth = 0; - int32_t displayHeight = 0; - /* * This is filled in by the WM relative to the frame and then translated * to absolute coordinates by SurfaceFlinger once the frame is computed. diff --git a/libs/gui/include/gui/WindowInfosListener.h b/libs/gui/include/gui/WindowInfosListener.h index 8a70b9bb57..a18a498c5e 100644 --- a/libs/gui/include/gui/WindowInfosListener.h +++ b/libs/gui/include/gui/WindowInfosListener.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include @@ -23,6 +24,7 @@ namespace android::gui { class WindowInfosListener : public virtual RefBase { public: - virtual void onWindowInfosChanged(const std::vector& /*windowInfos*/) = 0; + virtual void onWindowInfosChanged(const std::vector&, + const std::vector&) = 0; }; } // namespace android::gui \ No newline at end of file diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h index 7cb96e0a30..157a804264 100644 --- a/libs/gui/include/gui/WindowInfosListenerReporter.h +++ b/libs/gui/include/gui/WindowInfosListenerReporter.h @@ -21,7 +21,6 @@ #include #include #include -#include #include namespace android { @@ -30,7 +29,8 @@ class ISurfaceComposer; class WindowInfosListenerReporter : public gui::BnWindowInfosListener { public: static sp getInstance(); - binder::Status onWindowInfosChanged(const std::vector& windowInfos, + binder::Status onWindowInfosChanged(const std::vector&, + const std::vector&, const sp&) override; status_t addWindowInfosListener(const sp& windowInfosListener, diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index 3d26c3d858..6dd1073879 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -27,6 +27,7 @@ cc_test { "BufferQueue_test.cpp", "CpuConsumer_test.cpp", "EndToEndNativeInputTest.cpp", + "DisplayInfo_test.cpp", "DisplayedContentSampling_test.cpp", "FillBuffer.cpp", "GLTest.cpp", @@ -62,7 +63,7 @@ cc_test { "libinput", "libui", "libutils", - "libnativewindow" + "libnativewindow", ], header_libs: ["libsurfaceflinger_headers"], @@ -117,7 +118,7 @@ cc_test { "libgui", "libui", "libutils", - "libbufferhubqueue", // TODO(b/70046255): Remove these once BufferHub is integrated into libgui. + "libbufferhubqueue", // TODO(b/70046255): Remove these once BufferHub is integrated into libgui. "libpdx_default_transport", ], @@ -146,5 +147,5 @@ cc_test { "liblog", "libui", "libutils", - ] + ], } diff --git a/libs/gui/tests/DisplayInfo_test.cpp b/libs/gui/tests/DisplayInfo_test.cpp new file mode 100644 index 0000000000..df3329cd52 --- /dev/null +++ b/libs/gui/tests/DisplayInfo_test.cpp @@ -0,0 +1,49 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include + +namespace android { + +using gui::DisplayInfo; + +namespace test { + +TEST(DisplayInfo, Parcelling) { + DisplayInfo info; + info.displayId = 42; + info.logicalWidth = 99; + info.logicalHeight = 78; + info.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1}); + + Parcel p; + info.writeToParcel(&p); + p.setDataPosition(0); + + DisplayInfo info2; + info2.readFromParcel(&p); + ASSERT_EQ(info.displayId, info2.displayId); + ASSERT_EQ(info.logicalWidth, info2.logicalWidth); + ASSERT_EQ(info.logicalHeight, info2.logicalHeight); + ASSERT_EQ(info.transform, info2.transform); +} + +} // namespace test +} // namespace android diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp index a4f436cdba..dcdf76fe35 100644 --- a/libs/gui/tests/WindowInfo_test.cpp +++ b/libs/gui/tests/WindowInfo_test.cpp @@ -60,9 +60,6 @@ TEST(WindowInfo, Parcelling) { i.globalScaleFactor = 0.3; i.alpha = 0.7; i.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1}); - i.displayOrientation = ui::Transform::ROT_0; - i.displayWidth = 1000; - i.displayHeight = 2000; i.visible = false; i.focusable = false; i.hasWallpaper = false; @@ -100,8 +97,6 @@ TEST(WindowInfo, Parcelling) { ASSERT_EQ(i.globalScaleFactor, i2.globalScaleFactor); ASSERT_EQ(i.alpha, i2.alpha); ASSERT_EQ(i.transform, i2.transform); - ASSERT_EQ(i.displayWidth, i2.displayWidth); - ASSERT_EQ(i.displayHeight, i2.displayHeight); ASSERT_EQ(i.visible, i2.visible); ASSERT_EQ(i.focusable, i2.focusable); ASSERT_EQ(i.hasWallpaper, i2.hasWallpaper); diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 59cb419d2b..84f5a185d1 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -54,6 +54,7 @@ using android::base::HwTimeoutMultiplier; using android::base::Result; using android::base::StringPrintf; +using android::gui::DisplayInfo; using android::gui::FocusRequest; using android::gui::TouchOcclusionMode; using android::gui::WindowInfo; @@ -2444,9 +2445,15 @@ void InputDispatcher::addWindowTargetLocked(const sp& windowHa inputTarget.inputChannel = inputChannel; inputTarget.flags = targetFlags; inputTarget.globalScaleFactor = windowInfo->globalScaleFactor; - inputTarget.displayOrientation = windowInfo->displayOrientation; - inputTarget.displaySize = - int2(windowHandle->getInfo()->displayWidth, windowHandle->getInfo()->displayHeight); + const auto& displayInfoIt = mDisplayInfos.find(windowInfo->displayId); + if (displayInfoIt != mDisplayInfos.end()) { + const auto& displayInfo = displayInfoIt->second; + inputTarget.displayOrientation = displayInfo.transform.getOrientation(); + inputTarget.displaySize = int2(displayInfo.logicalWidth, displayInfo.logicalHeight); + } else { + ALOGI_IF(isPerWindowInputRotationEnabled(), + "DisplayInfo not found for window on display: %d", windowInfo->displayId); + } inputTargets.push_back(inputTarget); it = inputTargets.end() - 1; } @@ -4484,6 +4491,7 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked( void InputDispatcher::setInputWindows( const std::unordered_map>>& handlesPerDisplay) { + // TODO(b/198444055): Remove setInputWindows from InputDispatcher. { // acquire lock std::scoped_lock _l(mLock); for (const auto& [displayId, handles] : handlesPerDisplay) { @@ -5013,9 +5021,17 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { } if (!mWindowHandlesByDisplay.empty()) { - for (auto& it : mWindowHandlesByDisplay) { - const std::vector> windowHandles = it.second; - dump += StringPrintf(INDENT "Display: %" PRId32 "\n", it.first); + for (const auto& [displayId, windowHandles] : mWindowHandlesByDisplay) { + dump += StringPrintf(INDENT "Display: %" PRId32 "\n", displayId); + if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) { + const auto& displayInfo = it->second; + dump += StringPrintf(INDENT2 "logicalSize=%dx%d\n", displayInfo.logicalWidth, + displayInfo.logicalHeight); + displayInfo.transform.dump(dump, "transform", INDENT4); + } else { + dump += INDENT2 "No DisplayInfo found!\n"; + } + if (!windowHandles.empty()) { dump += INDENT2 "Windows:\n"; for (size_t i = 0; i < windowHandles.size(); i++) { @@ -5047,13 +5063,12 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { windowInfo->inputFeatures.string().c_str()); dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64 "ms, trustedOverlay=%s, hasToken=%s, " - "touchOcclusionMode=%s, displayOrientation=%d\n", + "touchOcclusionMode=%s\n", windowInfo->ownerPid, windowInfo->ownerUid, millis(windowInfo->dispatchingTimeout), toString(windowInfo->trustedOverlay), toString(windowInfo->token != nullptr), - toString(windowInfo->touchOcclusionMode).c_str(), - windowInfo->displayOrientation); + toString(windowInfo->touchOcclusionMode).c_str()); windowInfo->transform.dump(dump, "transform", INDENT4); } } else { @@ -6099,16 +6114,29 @@ void InputDispatcher::displayRemoved(int32_t displayId) { mLooper->wake(); } -void InputDispatcher::onWindowInfosChanged(const std::vector& windowInfos) { +void InputDispatcher::onWindowInfosChanged(const std::vector& windowInfos, + const std::vector& displayInfos) { // The listener sends the windows as a flattened array. Separate the windows by display for // more convenient parsing. std::unordered_map>> handlesPerDisplay; - for (const auto& info : windowInfos) { handlesPerDisplay.emplace(info.displayId, std::vector>()); handlesPerDisplay[info.displayId].push_back(new WindowInfoHandle(info)); } - setInputWindows(handlesPerDisplay); + + { // acquire lock + std::scoped_lock _l(mLock); + mDisplayInfos.clear(); + for (const auto& displayInfo : displayInfos) { + mDisplayInfos.emplace(displayInfo.displayId, displayInfo); + } + + for (const auto& [displayId, handles] : handlesPerDisplay) { + setInputWindowsLocked(handles, displayId); + } + } + // Wake up poll loop since it may need to make new input dispatching choices. + mLooper->wake(); } } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 6df333a154..afe4366c32 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -143,7 +143,8 @@ public: void displayRemoved(int32_t displayId) override; - void onWindowInfosChanged(const std::vector& windowInfos) override; + void onWindowInfosChanged(const std::vector&, + const std::vector&) override; private: enum class DropReason { @@ -337,8 +338,10 @@ private: float mMaximumObscuringOpacityForTouch GUARDED_BY(mLock); android::os::BlockUntrustedTouchesMode mBlockUntrustedTouchesMode GUARDED_BY(mLock); - std::unordered_map>> + std::unordered_map>> mWindowHandlesByDisplay GUARDED_BY(mLock); + std::unordered_map mDisplayInfos + GUARDED_BY(mLock); void setInputWindowsLocked( const std::vector>& inputWindowHandles, int32_t displayId) REQUIRES(mLock); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 802a17d981..fd93b2d8f7 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -139,6 +139,34 @@ uint32_t DisplayDevice::getPageFlipCount() const { return mCompositionDisplay->getRenderSurface()->getPageFlipCount(); } +std::pair DisplayDevice::getInputInfo() const { + gui::DisplayInfo info; + info.displayId = getLayerStack().id; + + // The physical orientation is set when the orientation of the display panel is + // different than the default orientation of the device. Other services like + // InputFlinger do not know about this, so we do not need to expose the physical + // orientation of the panel outside of SurfaceFlinger. + const ui::Rotation inversePhysicalOrientation = ui::ROTATION_0 - mPhysicalOrientation; + auto width = getWidth(); + auto height = getHeight(); + if (inversePhysicalOrientation == ui::ROTATION_90 || + inversePhysicalOrientation == ui::ROTATION_270) { + std::swap(width, height); + } + const ui::Transform undoPhysicalOrientation(ui::Transform::toRotationFlags( + inversePhysicalOrientation), + width, height); + const auto& displayTransform = undoPhysicalOrientation * getTransform(); + // Send the inverse display transform to input so it can convert display coordinates to + // logical display. + info.transform = displayTransform.inverse(); + + info.logicalWidth = getLayerStackSpaceRect().width(); + info.logicalHeight = getLayerStackSpaceRect().height(); + return {info, displayTransform}; +} + // ---------------------------------------------------------------------------- void DisplayDevice::setPowerMode(hal::PowerMode mode) { mPowerMode = mode; diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 43a6bd540a..7762054b4a 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -167,6 +167,10 @@ public: return mDeviceProductInfo; } + // Get the DisplayInfo that will be sent to InputFlinger, and the display transform that should + // be applied to all the input windows on the display. + std::pair getInputInfo() const; + /* ------------------------------------------------------------------------ * Display power mode management. */ diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 804cf9a3a0..2376b83c57 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2131,7 +2131,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet if (traceFlags & SurfaceTracing::TRACE_INPUT) { WindowInfo info; if (useDrawing) { - info = fillInputInfo(nullptr); + info = fillInputInfo(ui::Transform()); } else { info = state.inputInfo; } @@ -2265,7 +2265,7 @@ void Layer::fillTouchOcclusionMode(WindowInfo& info) { } } -WindowInfo Layer::fillInputInfo(const DisplayDevice* display) { +WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform) { if (!hasInputInfo()) { mDrawingState.inputInfo.name = getName(); mDrawingState.inputInfo.ownerUid = mOwnerUid; @@ -2279,35 +2279,6 @@ WindowInfo Layer::fillInputInfo(const DisplayDevice* display) { info.id = sequence; info.displayId = getLayerStack().id; - // Transform that maps from LayerStack space to display space, e.g. rotated to non-rotated. - // Used when InputFlinger operates in display space. - ui::Transform displayTransform; - if (display) { - // The physical orientation is set when the orientation of the display panel is different - // than the default orientation of the device. Other services like InputFlinger do not know - // about this, so we do not need to expose the physical orientation of the panel outside of - // SurfaceFlinger. - const ui::Rotation inversePhysicalOrientation = - ui::ROTATION_0 - display->getPhysicalOrientation(); - auto width = display->getWidth(); - auto height = display->getHeight(); - if (inversePhysicalOrientation == ui::ROTATION_90 || - inversePhysicalOrientation == ui::ROTATION_270) { - std::swap(width, height); - } - const ui::Transform undoPhysicalOrientation(ui::Transform::toRotationFlags( - inversePhysicalOrientation), - width, height); - displayTransform = undoPhysicalOrientation * display->getTransform(); - - // Send the inverse of the display orientation so that input can transform points back to - // the rotated display space. - const ui::Rotation inverseOrientation = ui::ROTATION_0 - display->getOrientation(); - info.displayOrientation = ui::Transform::toRotationFlags(inverseOrientation); - - info.displayWidth = width; - info.displayHeight = height; - } fillInputFrameInfo(info, displayTransform); // For compatibility reasons we let layers which can receive input diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 4200be4898..3c3c7d0b88 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -851,7 +851,7 @@ public: bool getPremultipledAlpha() const; void setInputInfo(const gui::WindowInfo& info); - gui::WindowInfo fillInputInfo(const DisplayDevice*); + gui::WindowInfo fillInputInfo(const ui::Transform& displayTransform); /** * Returns whether this layer has an explicitly set input-info. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 21b889e264..12389d1663 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -169,6 +169,7 @@ using namespace android::sysprop; using android::hardware::power::Boost; using base::StringAppendF; +using gui::DisplayInfo; using gui::IWindowInfosListener; using gui::WindowInfo; using ui::ColorMode; @@ -3053,6 +3054,16 @@ bool enablePerWindowInputRotation() { void SurfaceFlinger::notifyWindowInfos() { std::vector windowInfos; + std::vector displayInfos; + std::unordered_map displayTransforms; + + if (enablePerWindowInputRotation()) { + for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { + const auto& [info, transform] = display->getInputInfo(); + displayInfos.emplace_back(info); + displayTransforms.emplace(display.get(), transform); + } + } mDrawingState.traverseInReverseZOrder([&](Layer* layer) { if (!layer->needsInputInfo()) return; @@ -3064,9 +3075,11 @@ void SurfaceFlinger::notifyWindowInfos() { // When calculating the screen bounds we ignore the transparent region since it may // result in an unwanted offset. - windowInfos.push_back(layer->fillInputInfo(display)); + const auto it = displayTransforms.find(display); + windowInfos.push_back( + layer->fillInputInfo(it != displayTransforms.end() ? it->second : ui::Transform())); }); - mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, + mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos, mInputWindowCommands.syncInputWindows); } diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp index dc2aa58c9a..b93d127ab8 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp +++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp @@ -21,6 +21,7 @@ namespace android { +using gui::DisplayInfo; using gui::IWindowInfosListener; using gui::WindowInfo; @@ -67,6 +68,7 @@ void WindowInfosListenerInvoker::binderDied(const wp& who) { } void WindowInfosListenerInvoker::windowInfosChanged(const std::vector& windowInfos, + const std::vector& displayInfos, bool shouldSync) { std::unordered_set, ISurfaceComposer::SpHash> windowInfosListeners; @@ -81,7 +83,7 @@ void WindowInfosListenerInvoker::windowInfosChanged(const std::vectoronWindowInfosChanged(windowInfos, + listener->onWindowInfosChanged(windowInfos, displayInfos, shouldSync ? mWindowInfosReportedListener : nullptr); } } diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h index 5e5796fe2d..ecd797a631 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.h +++ b/services/surfaceflinger/WindowInfosListenerInvoker.h @@ -33,7 +33,8 @@ public: void addWindowInfosListener(const sp& windowInfosListener); void removeWindowInfosListener(const sp& windowInfosListener); - void windowInfosChanged(const std::vector& windowInfos, bool shouldSync); + void windowInfosChanged(const std::vector&, + const std::vector&, bool shouldSync); protected: void binderDied(const wp& who) override; diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp index de116f29ca..0069111e09 100644 --- a/services/surfaceflinger/tests/WindowInfosListener_test.cpp +++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp @@ -22,6 +22,7 @@ namespace android { using Transaction = SurfaceComposerClient::Transaction; +using gui::DisplayInfo; using gui::WindowInfo; class WindowInfosListenerTest : public ::testing::Test { @@ -40,7 +41,8 @@ protected: struct SyncWindowInfosListener : public gui::WindowInfosListener { public: - void onWindowInfosChanged(const std::vector& windowInfos) override { + void onWindowInfosChanged(const std::vector& windowInfos, + const std::vector&) override { windowInfosPromise.set_value(windowInfos); } -- cgit v1.2.3-59-g8ed1b From 8cd8a9977fe55520ba0d0a2f576efec8a2e9c84d Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Tue, 14 Sep 2021 23:22:49 +0200 Subject: RefreshRateConfigs: fix getMaxRefreshRateByPolicyLocked If there are no layers which are requesting a non seamless switch getMaxRefreshRateByPolicyLocked should return the max refresh rate from the group of the default mode (and not the group of the current mode). This fixes a bug where when the display mode is never reset to default after we exit an app which has called setFrameRate with changeFrameRateStrategy=Always. This change should have no affect phones, because there all modes are in the same config group. Bug: 199270559 Test: atest MatchContentFrameRateTest SetFrameRateTest Test: atest RefreshRateConfigsTest Change-Id: I6ff200a85edf026b0d04d4a06a13995832ffdab4 --- .../Scheduler/RefreshRateConfigs.cpp | 37 +++++++++++++--------- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 6 +++- .../tests/unittests/RefreshRateConfigsTest.cpp | 13 ++++++-- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index e922d46a40..b00423e6b7 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -330,18 +330,28 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( const bool hasExplicitVoteLayers = explicitDefaultVoteLayers > 0 || explicitExactOrMultipleVoteLayers > 0 || explicitExact > 0; + const Policy* policy = getCurrentPolicyLocked(); + const auto& defaultMode = mRefreshRates.at(policy->defaultMode); + // If the default mode group is different from the group of current mode, + // this means a layer requesting a seamed mode switch just disappeared and + // we should switch back to the default group. + // However if a seamed layer is still present we anchor around the group + // of the current mode, in order to prevent unnecessary seamed mode switches + // (e.g. when pausing a video playback). + const auto anchorGroup = seamedFocusedLayers > 0 ? mCurrentRefreshRate->getModeGroup() + : defaultMode->getModeGroup(); + // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've // selected a refresh rate to see if we should apply touch boost. if (globalSignals.touch && !hasExplicitVoteLayers) { ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str()); setTouchConsidered(); - return getMaxRefreshRateByPolicyLocked(); + return getMaxRefreshRateByPolicyLocked(anchorGroup); } // If the primary range consists of a single refresh rate then we can only // move out the of range if layers explicitly request a different refresh // rate. - const Policy* policy = getCurrentPolicyLocked(); const bool primaryRangeIsSingleRate = policy->primaryRange.min.equalsWithMargin(policy->primaryRange.max); @@ -353,7 +363,9 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( } if (layers.empty() || noVoteLayers == layers.size()) { - return getMaxRefreshRateByPolicyLocked(); + const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup); + ALOGV("no layers with votes - choose %s", refreshRate.getName().c_str()); + return refreshRate; } // Only if all layers want Min we should return Min @@ -370,8 +382,6 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( scores.emplace_back(RefreshRateScore{refreshRate, 0.0f}); } - const auto& defaultMode = mRefreshRates.at(policy->defaultMode); - for (const auto& layer : layers) { ALOGV("Calculating score for %s (%s, weight %.2f, desired %.2f) ", layer.name.c_str(), layerVoteTypeString(layer.vote).c_str(), layer.weight, @@ -409,10 +419,7 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( // mode group otherwise. In second case, if the current mode group is different // from the default, this means a layer with seamlessness=SeamedAndSeamless has just // disappeared. - const bool isInPolicyForDefault = seamedFocusedLayers > 0 - ? scores[i].refreshRate->getModeGroup() == mCurrentRefreshRate->getModeGroup() - : scores[i].refreshRate->getModeGroup() == defaultMode->getModeGroup(); - + const bool isInPolicyForDefault = scores[i].refreshRate->getModeGroup() == anchorGroup; if (layer.seamlessness == Seamlessness::Default && !isInPolicyForDefault) { ALOGV("%s ignores %s. Current mode = %s", formatLayerInfo(layer, weight).c_str(), scores[i].refreshRate->toString().c_str(), @@ -451,9 +458,9 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( // range instead of picking a random score from the app range. if (std::all_of(scores.begin(), scores.end(), [](RefreshRateScore score) { return score.score == 0; })) { - ALOGV("layers not scored - choose %s", - getMaxRefreshRateByPolicyLocked().getName().c_str()); - return getMaxRefreshRateByPolicyLocked(); + const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup); + ALOGV("layers not scored - choose %s", refreshRate.getName().c_str()); + return refreshRate; } else { return *bestRefreshRate; } @@ -463,7 +470,7 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( // interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit // vote we should not change it if we get a touch event. Only apply touch boost if it will // actually increase the refresh rate over the normal selection. - const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked(); + const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup); const bool touchBoostForExplicitExact = [&] { if (mSupportsFrameRateOverride) { @@ -646,10 +653,10 @@ RefreshRate RefreshRateConfigs::getMaxRefreshRateByPolicy() const { return getMaxRefreshRateByPolicyLocked(); } -const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const { +const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int anchorGroup) const { for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); it++) { const auto& refreshRate = (**it); - if (mCurrentRefreshRate->getModeGroup() == refreshRate.getModeGroup()) { + if (anchorGroup == refreshRate.getModeGroup()) { return refreshRate; } } diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 0d75689546..3713587393 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -388,7 +388,11 @@ private: // Returns the highest refresh rate according to the current policy. May change at runtime. Only // uses the primary range, not the app request range. - const RefreshRate& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock); + const RefreshRate& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock) { + return getMaxRefreshRateByPolicyLocked(mCurrentRefreshRate->getModeGroup()); + } + + const RefreshRate& getMaxRefreshRateByPolicyLocked(int anchorGroup) const REQUIRES(mLock); // Returns the current refresh rate, if allowed. Otherwise the default that is allowed by // the policy. diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index a6bfde791b..618c10d6ad 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -349,10 +349,19 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_noLayers) { EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}), - 0); + ASSERT_EQ(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}), + NO_ERROR); EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + + // We select max even when this will cause a non-seamless switch. + refreshRateConfigs = std::make_unique(m60_90DeviceWithDifferentGroups, + /*currentConfigId=*/HWC_CONFIG_ID_60); + ASSERT_EQ(refreshRateConfigs->setDisplayManagerPolicy( + {HWC_CONFIG_ID_90, /*allowGroupSwitching*/ true, {Fps(0), Fps(90)}}), + NO_ERROR); + EXPECT_EQ(mExpected90DifferentGroupConfig, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_90) { -- cgit v1.2.3-59-g8ed1b From 062a867e94dbf811ccca02e7a6a0f0e36465694a Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 3 Sep 2021 16:07:44 -0700 Subject: InputFlinger: Add DROP_INPUT and DROP_INPUT_IF_OBSCURED feature flags If a window has the feature DROP_INPUT set, then all touch and key events directed to the window will be dropped. For touch events, the events will not go to the window behind it. If a window has the feature DROP_INPUT_IF_OBSCURED set, then all touch and key events directed to the window will be dropped if the window is considered partially or fully obscured. These flags are used to enable features that allow for a less trusted interaction model between apps. See the bug for more details. Test: atest libgui_test InputDispatcherDropInputFeatureTest Bug:197364677 Change-Id: I71d7cf5064c8ce4626cff09b92e15ca38b39cbbe --- libs/gui/include/gui/WindowInfo.h | 8 +- .../inputflinger/dispatcher/InputDispatcher.cpp | 32 +++++ services/inputflinger/dispatcher/InputDispatcher.h | 4 + .../inputflinger/tests/InputDispatcher_test.cpp | 130 +++++++++++++++++++++ 4 files changed, 171 insertions(+), 3 deletions(-) diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index 47f6c05bff..2d36e3bd2f 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -132,9 +132,11 @@ struct WindowInfo : public Parcelable { }; enum class Feature : uint32_t { - DISABLE_TOUCH_PAD_GESTURES = 0x00000001, - NO_INPUT_CHANNEL = 0x00000002, - DISABLE_USER_ACTIVITY = 0x00000004, + DISABLE_TOUCH_PAD_GESTURES = 1u << 0, + NO_INPUT_CHANNEL = 1u << 1, + DISABLE_USER_ACTIVITY = 1u << 2, + DROP_INPUT = 1u << 3, + DROP_INPUT_IF_OBSCURED = 1u << 4, }; /* These values are filled in by the WM and passed through SurfaceFlinger diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 058e099faa..0d0d1c44f7 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -1868,6 +1868,11 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked( return InputEventInjectionResult::FAILED; } + // Drop key events if requested by input feature + if (focusedWindowHandle != nullptr && shouldDropInput(entry, focusedWindowHandle)) { + return InputEventInjectionResult::FAILED; + } + // Compatibility behavior: raise ANR if there is a focused application, but no focused window. // Only start counting when we have a focused event to dispatch. The ANR is canceled if we // start interacting with another application via touch (app switch). This code can be removed @@ -2113,6 +2118,11 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( } } + // Drop touch events if requested by input feature + if (newTouchedWindowHandle != nullptr && shouldDropInput(entry, newTouchedWindowHandle)) { + newTouchedWindowHandle = nullptr; + } + // Also don't send the new touch event to unresponsive gesture monitors newGestureMonitors = selectResponsiveMonitorsLocked(newGestureMonitors); @@ -2178,6 +2188,13 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( sp oldTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle(); newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState); + + // Drop touch events if requested by input feature + if (newTouchedWindowHandle != nullptr && + shouldDropInput(entry, newTouchedWindowHandle)) { + newTouchedWindowHandle = nullptr; + } + if (oldTouchedWindowHandle != newTouchedWindowHandle && oldTouchedWindowHandle != nullptr && newTouchedWindowHandle != nullptr) { if (DEBUG_FOCUS) { @@ -6180,4 +6197,19 @@ void InputDispatcher::onWindowInfosChanged(const std::vector& w setInputWindows(handlesPerDisplay); } +bool InputDispatcher::shouldDropInput( + const EventEntry& entry, const sp& windowHandle) const { + if (windowHandle->getInfo()->inputFeatures.test(WindowInfo::Feature::DROP_INPUT) || + (windowHandle->getInfo()->inputFeatures.test(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED) && + isWindowObscuredLocked(windowHandle))) { + ALOGW("Dropping %s event targeting %s as requested by input feature %s on display " + "%" PRId32 ".", + ftl::enum_string(entry.type).c_str(), windowHandle->getName().c_str(), + windowHandle->getInfo()->inputFeatures.string().c_str(), + windowHandle->getInfo()->displayId); + return true; + } + return false; +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index c09a89c26e..0db076f914 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -554,6 +554,10 @@ private: std::string getApplicationWindowLabel(const InputApplicationHandle* applicationHandle, const sp& windowHandle); + bool shouldDropInput(const EventEntry& entry, + const sp& windowHandle) const + REQUIRES(mLock); + // Manage the dispatch cycle for a single connection. // These methods are deliberately not Interruptible because doing all of the work // with the mutex held makes it easier to ensure that connection invariants are maintained. diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 0a91bde03b..226b547ffa 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -5471,4 +5471,134 @@ TEST_F(InputDispatcherDragTests, DragAndDrop_InvalidWindow) { mSecondWindow->assertNoEvents(); } +class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {}; + +TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) { + std::shared_ptr application = std::make_shared(); + sp window = + new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); + window->setInputFeatures(WindowInfo::Feature::DROP_INPUT); + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); + window->setFocusable(true); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + setFocusedWindow(window); + window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/); + + // With the flag set, window should not get any input + NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); + mDispatcher->notifyKey(&keyArgs); + window->assertNoEvents(); + + NotifyMotionArgs motionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); + mDispatcher->notifyMotion(&motionArgs); + window->assertNoEvents(); + + // With the flag cleared, the window should get input + window->setInputFeatures({}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + + keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); + mDispatcher->notifyKey(&keyArgs); + window->consumeKeyUp(ADISPLAY_ID_DEFAULT); + + motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); + mDispatcher->notifyMotion(&motionArgs); + window->consumeMotionDown(ADISPLAY_ID_DEFAULT); + window->assertNoEvents(); +} + +TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) { + std::shared_ptr obscuringApplication = + std::make_shared(); + sp obscuringWindow = + new FakeWindowHandle(obscuringApplication, mDispatcher, "obscuringWindow", + ADISPLAY_ID_DEFAULT); + obscuringWindow->setFrame(Rect(0, 0, 50, 50)); + obscuringWindow->setOwnerInfo(111, 111); + obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE); + std::shared_ptr application = std::make_shared(); + sp window = + new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); + window->setInputFeatures(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED); + window->setOwnerInfo(222, 222); + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); + window->setFocusable(true); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}}); + setFocusedWindow(window); + window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/); + + // With the flag set, window should not get any input + NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); + mDispatcher->notifyKey(&keyArgs); + window->assertNoEvents(); + + NotifyMotionArgs motionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); + mDispatcher->notifyMotion(&motionArgs); + window->assertNoEvents(); + + // With the flag cleared, the window should get input + window->setInputFeatures({}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}}); + + keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); + mDispatcher->notifyKey(&keyArgs); + window->consumeKeyUp(ADISPLAY_ID_DEFAULT); + + motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); + mDispatcher->notifyMotion(&motionArgs); + window->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED); + window->assertNoEvents(); +} + +TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) { + std::shared_ptr obscuringApplication = + std::make_shared(); + sp obscuringWindow = + new FakeWindowHandle(obscuringApplication, mDispatcher, "obscuringWindow", + ADISPLAY_ID_DEFAULT); + obscuringWindow->setFrame(Rect(0, 0, 50, 50)); + obscuringWindow->setOwnerInfo(111, 111); + obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE); + std::shared_ptr application = std::make_shared(); + sp window = + new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); + window->setInputFeatures(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED); + window->setOwnerInfo(222, 222); + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); + window->setFocusable(true); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}}); + setFocusedWindow(window); + window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/); + + // With the flag set, window should not get any input + NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); + mDispatcher->notifyKey(&keyArgs); + window->assertNoEvents(); + + NotifyMotionArgs motionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); + mDispatcher->notifyMotion(&motionArgs); + window->assertNoEvents(); + + // When the window is no longer obscured because it went on top, it should get input + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, obscuringWindow}}}); + + keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); + mDispatcher->notifyKey(&keyArgs); + window->consumeKeyUp(ADISPLAY_ID_DEFAULT); + + motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); + mDispatcher->notifyMotion(&motionArgs); + window->consumeMotionDown(ADISPLAY_ID_DEFAULT); + window->assertNoEvents(); +} + } // namespace android::inputdispatcher -- cgit v1.2.3-59-g8ed1b From 99d7c712ddc714e034aa5e114502c71772ef6abd Mon Sep 17 00:00:00 2001 From: Dmitri Plotnikov Date: Fri, 3 Sep 2021 19:07:23 -0700 Subject: Add reset() and setEnabled() to MultiStateCounter Bug: 197162116 Test: atest libbattery_test Change-Id: I14006af5e6a3e16d7849beb6def53de77b15b7bc --- libs/battery/MultiStateCounter.h | 87 ++++++++++++++++++++++++---------- libs/battery/MultiStateCounterTest.cpp | 77 ++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+), 24 deletions(-) diff --git a/libs/battery/MultiStateCounter.h b/libs/battery/MultiStateCounter.h index 40de068a95..e1ee07ccf1 100644 --- a/libs/battery/MultiStateCounter.h +++ b/libs/battery/MultiStateCounter.h @@ -42,6 +42,7 @@ class MultiStateCounter { T lastValue; time_t lastUpdateTimestamp; T deltaValue; + bool isEnabled; struct State { time_t timeInStateSinceUpdate; @@ -55,12 +56,16 @@ public: virtual ~MultiStateCounter(); + void setEnabled(bool enabled, time_t timestamp); + void setState(state_t state, time_t timestamp); void setValue(state_t state, const T& value); void updateValue(const T& value, time_t timestamp); + void reset(); + uint16_t getStateCount(); const T& getCount(state_t state); @@ -96,7 +101,8 @@ MultiStateCounter::MultiStateCounter(uint16_t stateCount, const T& emptyValue emptyValue(emptyValue), lastValue(emptyValue), lastUpdateTimestamp(-1), - deltaValue(emptyValue) { + deltaValue(emptyValue), + isEnabled(true) { states = new State[stateCount]; for (int i = 0; i < stateCount; i++) { states[i].timeInStateSinceUpdate = 0; @@ -110,8 +116,27 @@ MultiStateCounter::~MultiStateCounter() { }; template -void MultiStateCounter::setState(state_t state, time_t timestamp) { +void MultiStateCounter::setEnabled(bool enabled, time_t timestamp) { + if (enabled == isEnabled) { + return; + } + + if (!enabled) { + // Confirm the current state for the side-effect of updating the time-in-state + // counter for the current state. + setState(currentState, timestamp); + } + + isEnabled = enabled; + if (lastStateChangeTimestamp >= 0) { + lastStateChangeTimestamp = timestamp; + } +} + +template +void MultiStateCounter::setState(state_t state, time_t timestamp) { + if (isEnabled && lastStateChangeTimestamp >= 0) { if (timestamp >= lastStateChangeTimestamp) { states[currentState].timeInStateSinceUpdate += timestamp - lastStateChangeTimestamp; } else { @@ -137,37 +162,51 @@ void MultiStateCounter::setValue(state_t state, const T& value) { template void MultiStateCounter::updateValue(const T& value, time_t timestamp) { - // Confirm the current state for the side-effect of updating the time-in-state - // counter for the current state. - setState(currentState, timestamp); - - if (lastUpdateTimestamp >= 0) { - if (timestamp > lastUpdateTimestamp) { - if (delta(lastValue, value, &deltaValue)) { - time_t timeSinceUpdate = timestamp - lastUpdateTimestamp; - for (int i = 0; i < stateCount; i++) { - time_t timeInState = states[i].timeInStateSinceUpdate; - if (timeInState) { - add(&states[i].counter, deltaValue, timeInState, timeSinceUpdate); - states[i].timeInStateSinceUpdate = 0; + // If the counter is disabled, we ignore the update, except when the counter got disabled after + // the previous update, in which case we still need to pick up the residual delta. + if (isEnabled || lastUpdateTimestamp < lastStateChangeTimestamp) { + // Confirm the current state for the side-effect of updating the time-in-state + // counter for the current state. + setState(currentState, timestamp); + + if (lastUpdateTimestamp >= 0) { + if (timestamp > lastUpdateTimestamp) { + if (delta(lastValue, value, &deltaValue)) { + time_t timeSinceUpdate = timestamp - lastUpdateTimestamp; + for (int i = 0; i < stateCount; i++) { + time_t timeInState = states[i].timeInStateSinceUpdate; + if (timeInState) { + add(&states[i].counter, deltaValue, timeInState, timeSinceUpdate); + states[i].timeInStateSinceUpdate = 0; + } } + } else { + std::stringstream str; + str << "updateValue is called with a value " << valueToString(value) + << ", which is lower than the previous value " << valueToString(lastValue) + << "\n"; + ALOGE("%s", str.str().c_str()); } - } else { - std::stringstream str; - str << "updateValue is called with a value " << valueToString(value) - << ", which is lower than the previous value " << valueToString(lastValue) - << "\n"; - ALOGE("%s", str.str().c_str()); + } else if (timestamp < lastUpdateTimestamp) { + ALOGE("updateValue is called with an earlier timestamp: %lu, previous: %lu\n", + (unsigned long)timestamp, (unsigned long)lastUpdateTimestamp); } - } else if (timestamp < lastUpdateTimestamp) { - ALOGE("updateValue is called with an earlier timestamp: %lu, previous timestamp: %lu\n", - (unsigned long)timestamp, (unsigned long)lastUpdateTimestamp); } } lastValue = value; lastUpdateTimestamp = timestamp; } +template +void MultiStateCounter::reset() { + lastStateChangeTimestamp = -1; + lastUpdateTimestamp = -1; + for (int i = 0; i < stateCount; i++) { + states[i].timeInStateSinceUpdate = 0; + states[i].counter = emptyValue; + } +} + template uint16_t MultiStateCounter::getStateCount() { return stateCount; diff --git a/libs/battery/MultiStateCounterTest.cpp b/libs/battery/MultiStateCounterTest.cpp index 87c80c53d3..319ba76a4f 100644 --- a/libs/battery/MultiStateCounterTest.cpp +++ b/libs/battery/MultiStateCounterTest.cpp @@ -71,6 +71,83 @@ TEST_F(MultiStateCounterTest, stateChange) { EXPECT_DOUBLE_EQ(4.0, testCounter.getCount(2)); } +TEST_F(MultiStateCounterTest, setEnabled) { + DoubleMultiStateCounter testCounter(3, 0); + testCounter.updateValue(0, 0); + testCounter.setState(1, 0); + testCounter.setEnabled(false, 1000); + testCounter.setState(2, 2000); + testCounter.updateValue(6.0, 3000); + + // In state 1: accumulated 1000 before disabled, that's 6.0 * 1000/3000 = 2.0 + // In state 2: 0, since it is still disabled + EXPECT_DOUBLE_EQ(0, testCounter.getCount(0)); + EXPECT_DOUBLE_EQ(2.0, testCounter.getCount(1)); + EXPECT_DOUBLE_EQ(0, testCounter.getCount(2)); + + // Should have no effect since the counter is disabled + testCounter.setState(0, 3500); + + // Should have no effect since the counter is disabled + testCounter.updateValue(10.0, 4000); + + EXPECT_DOUBLE_EQ(0, testCounter.getCount(0)); + EXPECT_DOUBLE_EQ(2.0, testCounter.getCount(1)); + EXPECT_DOUBLE_EQ(0, testCounter.getCount(2)); + + testCounter.setState(2, 4500); + + // Enable the counter to partially accumulate deltas for the current state, 2 + testCounter.setEnabled(true, 5000); + testCounter.setEnabled(false, 6000); + testCounter.setEnabled(true, 7000); + testCounter.updateValue(20.0, 8000); + + // The delta is 10.0 over 5000-3000=2000. + // Counter has been enabled in state 2 for (6000-5000)+(8000-7000) = 2000, + // so its share is (20.0-10.0) * 2000/(8000-4000) = 5.0 + EXPECT_DOUBLE_EQ(0, testCounter.getCount(0)); + EXPECT_DOUBLE_EQ(2.0, testCounter.getCount(1)); + EXPECT_DOUBLE_EQ(5.0, testCounter.getCount(2)); + + testCounter.reset(); + testCounter.setState(0, 0); + testCounter.updateValue(0, 0); + testCounter.setState(1, 2000); + testCounter.setEnabled(false, 3000); + testCounter.updateValue(200, 5000); + + // 200 over 5000 = 40 per second + // Counter was in state 0 from 0 to 2000, so 2 sec, so the count should be 40 * 2 = 80 + // It stayed in state 1 from 2000 to 3000, at which point the counter was disabled, + // so the count for state 1 should be 40 * 1 = 40. + // The remaining 2 seconds from 3000 to 5000 don't count because the counter was disabled. + EXPECT_DOUBLE_EQ(80.0, testCounter.getCount(0)); + EXPECT_DOUBLE_EQ(40.0, testCounter.getCount(1)); + EXPECT_DOUBLE_EQ(0, testCounter.getCount(2)); +} + +TEST_F(MultiStateCounterTest, reset) { + DoubleMultiStateCounter testCounter(3, 0); + testCounter.updateValue(0, 0); + testCounter.setState(1, 0); + testCounter.updateValue(2.72, 3000); + + testCounter.reset(); + + EXPECT_DOUBLE_EQ(0, testCounter.getCount(0)); + EXPECT_DOUBLE_EQ(0, testCounter.getCount(1)); + EXPECT_DOUBLE_EQ(0, testCounter.getCount(2)); + + // Assert that we can still continue accumulating after a reset + testCounter.updateValue(0, 4000); + testCounter.updateValue(3.14, 5000); + + EXPECT_DOUBLE_EQ(0, testCounter.getCount(0)); + EXPECT_DOUBLE_EQ(3.14, testCounter.getCount(1)); + EXPECT_DOUBLE_EQ(0, testCounter.getCount(2)); +} + TEST_F(MultiStateCounterTest, timeAdjustment_setState) { DoubleMultiStateCounter testCounter(3, 0); testCounter.updateValue(0, 0); -- cgit v1.2.3-59-g8ed1b From 248bce89cac382462dac0e1bc9cea5488d5b33cf Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 16 Sep 2021 14:29:59 -0700 Subject: SF: trace vsyncPeriod from onComposerHalVsync Test: manual Change-Id: Ie447c65eafc11e6c1c0bc32401501b1499a73e6b --- services/surfaceflinger/SurfaceFlinger.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5a881a3dfe..c7e5dff803 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1710,7 +1710,15 @@ nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const { void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp, std::optional vsyncPeriod) { - ATRACE_CALL(); + const std::string tracePeriod = [vsyncPeriod]() { + if (ATRACE_ENABLED() && vsyncPeriod) { + std::stringstream ss; + ss << "(" << *vsyncPeriod << ")"; + return ss.str(); + } + return std::string(); + }(); + ATRACE_FORMAT("onComposerHalVsync%s", tracePeriod.c_str()); Mutex::Autolock lock(mStateLock); const auto displayId = getHwComposer().toPhysicalDisplayId(hwcDisplayId); -- cgit v1.2.3-59-g8ed1b From 05243be5e9d22687852d989d3ce28748d66db255 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 16 Sep 2021 15:58:52 -0700 Subject: SF: give a higher score to frame rates which exact matches To avoid cases where devices with very close refresh rates (such as 53Hz and 55Hz) gives the same score for these, assign a small (0.99) factor to frame rate that are not exact match of a multiple of the refresh rate Test: atest FrameRateCtsActivity Test: atest RefreshRateConfigsTest Bug: 190578904 Change-Id: Idd32600ccacc0cad8f44c9d9373e50a333663717 --- .../Scheduler/RefreshRateConfigs.cpp | 62 ++++++++++++++-------- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 3 ++ .../tests/unittests/RefreshRateConfigsTest.cpp | 39 +++++++++++++- 3 files changed, 80 insertions(+), 24 deletions(-) diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index e922d46a40..f72fb15a53 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -133,27 +133,10 @@ bool RefreshRateConfigs::isVoteAllowed(const LayerRequirement& layer, return true; } -float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer, - const RefreshRate& refreshRate, - bool isSeamlessSwitch) const { - if (!isVoteAllowed(layer, refreshRate)) { - return 0; - } - +float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked( + const LayerRequirement& layer, const RefreshRate& refreshRate) const { constexpr float kScoreForFractionalPairs = .8f; - // Slightly prefer seamless switches. - constexpr float kSeamedSwitchPenalty = 0.95f; - const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty; - - // If the layer wants Max, give higher score to the higher refresh rate - if (layer.vote == LayerVoteType::Max) { - const auto ratio = refreshRate.getFps().getValue() / - mAppRequestRefreshRates.back()->getFps().getValue(); - // use ratio^2 to get a lower score the more we get further from peak - return ratio * ratio; - } - const auto displayPeriod = refreshRate.getVsyncPeriod(); const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs(); if (layer.vote == LayerVoteType::ExplicitDefault) { @@ -178,7 +161,7 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye if (layer.vote == LayerVoteType::ExplicitExactOrMultiple || layer.vote == LayerVoteType::Heuristic) { if (isFractionalPairOrMultiple(refreshRate.getFps(), layer.desiredRefreshRate)) { - return kScoreForFractionalPairs * seamlessness; + return kScoreForFractionalPairs; } // Calculate how many display vsyncs we need to present a single frame for this @@ -188,7 +171,7 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1 if (displayFramesRemainder == 0) { // Layer desired refresh rate matches the display rate. - return 1.0f * seamlessness; + return 1.0f; } if (displayFramesQuotient == 0) { @@ -206,7 +189,29 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye iter++; } - return (1.0f / iter) * seamlessness; + return (1.0f / iter); + } + + return 0; +} + +float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer, + const RefreshRate& refreshRate, + bool isSeamlessSwitch) const { + if (!isVoteAllowed(layer, refreshRate)) { + return 0; + } + + // Slightly prefer seamless switches. + constexpr float kSeamedSwitchPenalty = 0.95f; + const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty; + + // If the layer wants Max, give higher score to the higher refresh rate + if (layer.vote == LayerVoteType::Max) { + const auto ratio = refreshRate.getFps().getValue() / + mAppRequestRefreshRates.back()->getFps().getValue(); + // use ratio^2 to get a lower score the more we get further from peak + return ratio * ratio; } if (layer.vote == LayerVoteType::ExplicitExact) { @@ -221,7 +226,18 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye return divider == 1; } - return 0; + // If the layer frame rate is a divider of the refresh rate it should score + // the highest score. + if (getFrameRateDivider(refreshRate.getFps(), layer.desiredRefreshRate) > 0) { + return 1.0f * seamlessness; + } + + // The layer frame rate is not a divider of the refresh rate, + // there is a small penalty attached to the score to favor the frame rates + // the exactly matches the display refresh rate or a multiple. + constexpr float kNonExactMatchingPenalty = 0.99f; + return calculateNonExactMatchingLayerScoreLocked(layer, refreshRate) * seamlessness * + kNonExactMatchingPenalty; } struct RefreshRateScore { diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 0d75689546..8b895f5771 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -405,6 +405,9 @@ private: float calculateLayerScoreLocked(const LayerRequirement&, const RefreshRate&, bool isSeamlessSwitch) const REQUIRES(mLock); + float calculateNonExactMatchingLayerScoreLocked(const LayerRequirement&, + const RefreshRate&) const REQUIRES(mLock); + void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock); // The list of refresh rates, indexed by display modes ID. This may change after this diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index a6bfde791b..4681c37746 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -175,7 +175,6 @@ protected: RefreshRate mExpected30Config = {mConfig30, RefreshRate::ConstructorTag(0)}; RefreshRate mExpected120Config = {mConfig120, RefreshRate::ConstructorTag(0)}; -private: DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod, ui::Size resolution = ui::Size()); }; @@ -2170,6 +2169,44 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_FractionalRefreshRates_ExactAn refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); } +// b/190578904 +TEST_F(RefreshRateConfigsTest, getBestRefreshRate_deviceWithCloseRefreshRates) { + constexpr int kMinRefreshRate = 10; + constexpr int kMaxRefreshRate = 240; + + DisplayModes displayModes; + for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) { + constexpr int32_t kGroup = 0; + const auto refreshRate = Fps(static_cast(fps)); + displayModes.push_back( + createDisplayMode(DisplayModeId(fps), kGroup, refreshRate.getPeriodNsecs())); + } + + const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false}; + auto refreshRateConfigs = + std::make_unique(displayModes, + /*currentConfigId=*/displayModes[0]->getId()); + + auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + const auto testRefreshRate = [&](Fps fps, LayerVoteType vote) { + layers[0].desiredRefreshRate = fps; + layers[0].vote = vote; + EXPECT_EQ(fps.getIntValue(), + refreshRateConfigs->getBestRefreshRate(layers, globalSignals) + .getFps() + .getIntValue()) + << "Failed for " << RefreshRateConfigs::layerVoteTypeString(vote); + }; + + for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) { + const auto refreshRate = Fps(static_cast(fps)); + testRefreshRate(refreshRate, LayerVoteType::Heuristic); + testRefreshRate(refreshRate, LayerVoteType::ExplicitDefault); + testRefreshRate(refreshRate, LayerVoteType::ExplicitExactOrMultiple); + testRefreshRate(refreshRate, LayerVoteType::ExplicitExact); + } +} + TEST_F(RefreshRateConfigsTest, testComparisonOperator) { EXPECT_TRUE(mExpected60Config < mExpected90Config); EXPECT_FALSE(mExpected60Config < mExpected60Config); -- cgit v1.2.3-59-g8ed1b From b9b18509a6d0f5f074e86802b322a4fb01b43cd5 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 26 Aug 2021 12:30:32 -0700 Subject: Add display transform to MotionEvent for raw coords Since input now works in display coordinates, we need to include the display projection with MotionEvent so that the getRaw API can continue to report logical display coordinates. It is also important to highlight the difference in the coordinate systems used by regular input windows and input monitors. MotionEvents coming from input monitors will always report values in unrotated logical display coordinates, because we do not yet have an API to report unrotated values in MotionEvents. Bug: 179274888 Test: presubmit Test: manual, ensure input works Change-Id: Ief3b2b31c6644beaa2f8c4b90302f441f93ab960 --- include/input/Input.h | 12 +- include/input/InputTransport.h | 29 +-- libs/input/Input.cpp | 83 +++----- libs/input/InputTransport.cpp | 40 ++-- libs/input/tests/InputEvent_test.cpp | 216 +++++++++------------ .../input/tests/InputPublisherAndConsumer_test.cpp | 89 ++++----- libs/input/tests/StructLayout_test.cpp | 14 +- libs/input/tests/VelocityTracker_test.cpp | 3 +- libs/input/tests/VerifiedInputEvent_test.cpp | 4 +- .../benchmarks/InputDispatcher_benchmarks.cpp | 4 +- services/inputflinger/dispatcher/Entry.cpp | 7 +- services/inputflinger/dispatcher/Entry.h | 7 +- .../inputflinger/dispatcher/InputDispatcher.cpp | 63 +++--- services/inputflinger/dispatcher/InputDispatcher.h | 3 +- services/inputflinger/dispatcher/InputTarget.h | 7 +- .../inputflinger/tests/InputDispatcher_test.cpp | 47 ++--- 16 files changed, 280 insertions(+), 348 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index f170f0fa23..d397313ab6 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -579,9 +579,7 @@ public: void setCursorPosition(float x, float y); - uint32_t getDisplayOrientation() const { return mDisplayOrientation; } - - int2 getDisplaySize() const { return {mDisplayWidth, mDisplayHeight}; } + ui::Transform getRawTransform() const { return mRawTransform; } static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); } @@ -757,8 +755,8 @@ public: int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, MotionClassification classification, const ui::Transform& transform, float xPrecision, float yPrecision, float rawXCursorPosition, - float rawYCursorPosition, uint32_t displayOrientation, int32_t displayWidth, - int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, + float rawYCursorPosition, const ui::Transform& rawTransform, nsecs_t downTime, + nsecs_t eventTime, size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); void copyFrom(const MotionEvent* other, bool keepHistory); @@ -816,9 +814,7 @@ protected: float mYPrecision; float mRawXCursorPosition; float mRawYCursorPosition; - uint32_t mDisplayOrientation; - int32_t mDisplayWidth; - int32_t mDisplayHeight; + ui::Transform mRawTransform; nsecs_t mDownTime; Vector mPointerProperties; std::vector mSampleEventTimes; diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 7632b30bd2..d655b28278 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -114,7 +114,7 @@ struct InputMessage { struct Motion { int32_t eventId; - uint32_t empty1; + uint32_t pointerCount; nsecs_t eventTime __attribute__((aligned(8))); int32_t deviceId; int32_t source; @@ -129,20 +129,22 @@ struct InputMessage { uint8_t empty2[3]; // 3 bytes to fill gap created by classification int32_t edgeFlags; nsecs_t downTime __attribute__((aligned(8))); - float dsdx; - float dtdx; - float dtdy; - float dsdy; - float tx; - float ty; + float dsdx; // Begin window transform + float dtdx; // + float dtdy; // + float dsdy; // + float tx; // + float ty; // End window transform float xPrecision; float yPrecision; float xCursorPosition; float yCursorPosition; - uint32_t displayOrientation; - int32_t displayWidth; - int32_t displayHeight; - uint32_t pointerCount; + float dsdxRaw; // Begin raw transform + float dtdxRaw; // + float dtdyRaw; // + float dsdyRaw; // + float txRaw; // + float tyRaw; // End raw transform /** * The "pointers" field must be the last field of the struct InputMessage. * When we send the struct InputMessage across the socket, we are not @@ -367,9 +369,8 @@ public: int32_t metaState, int32_t buttonState, MotionClassification classification, const ui::Transform& transform, float xPrecision, float yPrecision, float xCursorPosition, - float yCursorPosition, uint32_t displayOrientation, - int32_t displayWidth, int32_t displayHeight, nsecs_t downTime, - nsecs_t eventTime, uint32_t pointerCount, + float yCursorPosition, const ui::Transform& rawTransform, + nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 037849eac4..30e5d5b0bc 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -76,36 +76,13 @@ float transformAngle(const ui::Transform& transform, float angleRadians) { return result; } -// Rotates the given point to the specified orientation. If the display width and height are -// provided, the point is rotated in the screen space. Otherwise, the point is rotated about the -// origin. This helper is used to avoid the extra overhead of creating new Transforms. -vec2 rotatePoint(uint32_t orientation, float x, float y, int32_t displayWidth = 0, - int32_t displayHeight = 0) { - if (orientation == ui::Transform::ROT_0) { - return {x, y}; - } - - vec2 xy(x, y); - if (orientation == ui::Transform::ROT_90) { - xy.x = displayHeight - y; - xy.y = x; - } else if (orientation == ui::Transform::ROT_180) { - xy.x = displayWidth - x; - xy.y = displayHeight - y; - } else if (orientation == ui::Transform::ROT_270) { - xy.x = y; - xy.y = displayWidth - x; - } - return xy; -} - -vec2 applyTransformWithoutTranslation(const ui::Transform& transform, float x, float y) { +vec2 transformWithoutTranslation(const ui::Transform& transform, float x, float y) { const vec2 transformedXy = transform.transform(x, y); const vec2 transformedOrigin = transform.transform(0, 0); return transformedXy - transformedOrigin; } -bool shouldDisregardWindowTranslation(uint32_t source) { +bool shouldDisregardTranslation(uint32_t source) { // Pointer events are the only type of events that refer to absolute coordinates on the display, // so we should apply the entire window transform. For other types of events, we should make // sure to not apply the window translation/offset. @@ -431,8 +408,7 @@ void MotionEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int3 int32_t buttonState, MotionClassification classification, const ui::Transform& transform, float xPrecision, float yPrecision, float rawXCursorPosition, float rawYCursorPosition, - uint32_t displayOrientation, int32_t displayWidth, - int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, + const ui::Transform& rawTransform, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { InputEvent::initialize(id, deviceId, source, displayId, hmac); @@ -448,9 +424,7 @@ void MotionEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int3 mYPrecision = yPrecision; mRawXCursorPosition = rawXCursorPosition; mRawYCursorPosition = rawYCursorPosition; - mDisplayOrientation = displayOrientation; - mDisplayWidth = displayWidth; - mDisplayHeight = displayHeight; + mRawTransform = rawTransform; mDownTime = downTime; mPointerProperties.clear(); mPointerProperties.appendArray(pointerProperties, pointerCount); @@ -474,9 +448,7 @@ void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { mYPrecision = other->mYPrecision; mRawXCursorPosition = other->mRawXCursorPosition; mRawYCursorPosition = other->mRawYCursorPosition; - mDisplayOrientation = other->mDisplayOrientation; - mDisplayWidth = other->mDisplayWidth; - mDisplayHeight = other->mDisplayHeight; + mRawTransform = other->mRawTransform; mDownTime = other->mDownTime; mPointerProperties = other->mPointerProperties; @@ -542,20 +514,19 @@ float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex, if (!isPerWindowInputRotationEnabled()) return coords->getAxisValue(axis); if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) { - // For compatibility, convert raw coordinates into "oriented screen space". Once app - // developers are educated about getRaw, we can consider removing this. - const vec2 xy = shouldDisregardWindowTranslation(mSource) - ? rotatePoint(mDisplayOrientation, coords->getX(), coords->getY()) - : rotatePoint(mDisplayOrientation, coords->getX(), coords->getY(), mDisplayWidth, - mDisplayHeight); + // For compatibility, convert raw coordinates into logical display space. + const vec2 xy = shouldDisregardTranslation(mSource) + ? transformWithoutTranslation(mRawTransform, coords->getX(), coords->getY()) + : mRawTransform.transform(coords->getX(), coords->getY()); static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); return xy[axis]; } if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) { - // For compatibility, since we convert raw coordinates into "oriented screen space", we + // For compatibility, since we report raw coordinates in logical display space, we // need to convert the relative axes into the same orientation for consistency. - const vec2 relativeXy = rotatePoint(mDisplayOrientation, + const vec2 relativeXy = + transformWithoutTranslation(mRawTransform, coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)); return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y; @@ -569,8 +540,8 @@ float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex); if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) { - const vec2 xy = shouldDisregardWindowTranslation(mSource) - ? applyTransformWithoutTranslation(mTransform, coords->getX(), coords->getY()) + const vec2 xy = shouldDisregardTranslation(mSource) + ? transformWithoutTranslation(mTransform, coords->getX(), coords->getY()) : mTransform.transform(coords->getXYValue()); static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); return xy[axis]; @@ -578,11 +549,9 @@ float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) { const vec2 relativeXy = - applyTransformWithoutTranslation(mTransform, - coords->getAxisValue( - AMOTION_EVENT_AXIS_RELATIVE_X), - coords->getAxisValue( - AMOTION_EVENT_AXIS_RELATIVE_Y)); + transformWithoutTranslation(mTransform, + coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), + coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)); return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y; } @@ -607,6 +576,8 @@ void MotionEvent::offsetLocation(float xOffset, float yOffset) { void MotionEvent::scale(float globalScaleFactor) { mTransform.set(mTransform.tx() * globalScaleFactor, mTransform.ty() * globalScaleFactor); + mRawTransform.set(mRawTransform.tx() * globalScaleFactor, + mRawTransform.ty() * globalScaleFactor); mXPrecision *= globalScaleFactor; mYPrecision *= globalScaleFactor; @@ -708,9 +679,11 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { mYPrecision = parcel->readFloat(); mRawXCursorPosition = parcel->readFloat(); mRawYCursorPosition = parcel->readFloat(); - mDisplayOrientation = parcel->readUint32(); - mDisplayWidth = parcel->readInt32(); - mDisplayHeight = parcel->readInt32(); + + result = android::readFromParcel(mRawTransform, *parcel); + if (result != OK) { + return result; + } mDownTime = parcel->readInt64(); mPointerProperties.clear(); @@ -770,9 +743,11 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeFloat(mYPrecision); parcel->writeFloat(mRawXCursorPosition); parcel->writeFloat(mRawYCursorPosition); - parcel->writeUint32(mDisplayOrientation); - parcel->writeInt32(mDisplayWidth); - parcel->writeInt32(mDisplayHeight); + + result = android::writeToParcel(mRawTransform, *parcel); + if (result != OK) { + return result; + } parcel->writeInt64(mDownTime); for (size_t i = 0; i < pointerCount; i++) { diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 91ab008161..02a5a0807b 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -203,6 +203,8 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const { case InputMessage::Type::MOTION: { // int32_t eventId msg->body.motion.eventId = body.motion.eventId; + // uint32_t pointerCount + msg->body.motion.pointerCount = body.motion.pointerCount; // nsecs_t eventTime msg->body.motion.eventTime = body.motion.eventTime; // int32_t deviceId @@ -245,14 +247,14 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const { msg->body.motion.xCursorPosition = body.motion.xCursorPosition; // float yCursorPosition msg->body.motion.yCursorPosition = body.motion.yCursorPosition; - // uint32_t displayOrientation - msg->body.motion.displayOrientation = body.motion.displayOrientation; - // int32_t displayWidth - msg->body.motion.displayWidth = body.motion.displayWidth; - // int32_t displayHeight - msg->body.motion.displayHeight = body.motion.displayHeight; - // uint32_t pointerCount - msg->body.motion.pointerCount = body.motion.pointerCount; + + msg->body.motion.dsdxRaw = body.motion.dsdxRaw; + msg->body.motion.dtdxRaw = body.motion.dtdxRaw; + msg->body.motion.dtdyRaw = body.motion.dtdyRaw; + msg->body.motion.dsdyRaw = body.motion.dsdyRaw; + msg->body.motion.txRaw = body.motion.txRaw; + msg->body.motion.tyRaw = body.motion.tyRaw; + //struct Pointer pointers[MAX_POINTERS] for (size_t i = 0; i < body.motion.pointerCount; i++) { // PointerProperties properties @@ -542,8 +544,8 @@ status_t InputPublisher::publishMotionEvent( std::array hmac, int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, MotionClassification classification, const ui::Transform& transform, float xPrecision, - float yPrecision, float xCursorPosition, float yCursorPosition, uint32_t displayOrientation, - int32_t displayWidth, int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, + float yPrecision, float xCursorPosition, float yCursorPosition, + const ui::Transform& rawTransform, nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { if (ATRACE_ENABLED()) { @@ -603,9 +605,12 @@ status_t InputPublisher::publishMotionEvent( msg.body.motion.yPrecision = yPrecision; msg.body.motion.xCursorPosition = xCursorPosition; msg.body.motion.yCursorPosition = yCursorPosition; - msg.body.motion.displayOrientation = displayOrientation; - msg.body.motion.displayWidth = displayWidth; - msg.body.motion.displayHeight = displayHeight; + msg.body.motion.dsdxRaw = rawTransform.dsdx(); + msg.body.motion.dtdxRaw = rawTransform.dtdx(); + msg.body.motion.dtdyRaw = rawTransform.dtdy(); + msg.body.motion.dsdyRaw = rawTransform.dsdy(); + msg.body.motion.txRaw = rawTransform.tx(); + msg.body.motion.tyRaw = rawTransform.ty(); msg.body.motion.downTime = downTime; msg.body.motion.eventTime = eventTime; msg.body.motion.pointerCount = pointerCount; @@ -1391,6 +1396,10 @@ void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage ui::Transform transform; transform.set({msg->body.motion.dsdx, msg->body.motion.dtdx, msg->body.motion.tx, msg->body.motion.dtdy, msg->body.motion.dsdy, msg->body.motion.ty, 0, 0, 1}); + ui::Transform displayTransform; + displayTransform.set({msg->body.motion.dsdxRaw, msg->body.motion.dtdxRaw, + msg->body.motion.txRaw, msg->body.motion.dtdyRaw, + msg->body.motion.dsdyRaw, msg->body.motion.tyRaw, 0, 0, 1}); event->initialize(msg->body.motion.eventId, msg->body.motion.deviceId, msg->body.motion.source, msg->body.motion.displayId, msg->body.motion.hmac, msg->body.motion.action, msg->body.motion.actionButton, msg->body.motion.flags, @@ -1398,9 +1407,8 @@ void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage msg->body.motion.buttonState, msg->body.motion.classification, transform, msg->body.motion.xPrecision, msg->body.motion.yPrecision, msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition, - msg->body.motion.displayOrientation, msg->body.motion.displayWidth, - msg->body.motion.displayHeight, msg->body.motion.downTime, - msg->body.motion.eventTime, pointerCount, pointerProperties, pointerCoords); + displayTransform, msg->body.motion.downTime, msg->body.motion.eventTime, + pointerCount, pointerProperties, pointerCoords); } void InputConsumer::initializeTouchModeEvent(TouchModeEvent* event, const InputMessage* msg) { diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index b1ef7534e4..7e7dfd5416 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -226,11 +226,16 @@ protected: static constexpr float Y_SCALE = 3.0; static constexpr float X_OFFSET = 1; static constexpr float Y_OFFSET = 1.1; + static constexpr float RAW_X_SCALE = 4.0; + static constexpr float RAW_Y_SCALE = -5.0; + static constexpr float RAW_X_OFFSET = 12; + static constexpr float RAW_Y_OFFSET = -41.1; static const std::optional INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE; int32_t mId; ui::Transform mTransform; + ui::Transform mRawTransform; void SetUp() override; void TearDown() override; @@ -259,6 +264,7 @@ void MotionEventTest::TearDown() { void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { mId = InputEvent::nextId(); mTransform.set({X_SCALE, 0, X_OFFSET, 0, Y_SCALE, Y_OFFSET, 0, 0, 1}); + mRawTransform.set({RAW_X_SCALE, 0, RAW_X_OFFSET, 0, RAW_Y_SCALE, RAW_Y_OFFSET, 0, 0, 1}); PointerProperties pointerProperties[2]; pointerProperties[0].clear(); @@ -294,9 +300,8 @@ void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, MotionClassification::NONE, mTransform, 2.0f, 2.1f, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, - ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2, pointerProperties, - pointerCoords); + mRawTransform, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2, + pointerProperties, pointerCoords); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111); @@ -373,39 +378,37 @@ void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) { ASSERT_EQ(ARBITRARY_EVENT_TIME + 1, event->getHistoricalEventTime(1)); ASSERT_EQ(ARBITRARY_EVENT_TIME + 2, event->getEventTime()); - ASSERT_EQ(11, event->getHistoricalRawPointerCoords(0, 0)-> - getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(21, event->getHistoricalRawPointerCoords(1, 0)-> - getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(111, event->getHistoricalRawPointerCoords(0, 1)-> - getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(121, event->getHistoricalRawPointerCoords(1, 1)-> - getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(211, event->getRawPointerCoords(0)-> - getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(221, event->getRawPointerCoords(1)-> - getAxisValue(AMOTION_EVENT_AXIS_Y)); - - ASSERT_EQ(11, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0)); - ASSERT_EQ(21, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0)); - ASSERT_EQ(111, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1)); - ASSERT_EQ(121, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1)); - ASSERT_EQ(211, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0)); - ASSERT_EQ(221, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1)); - - ASSERT_EQ(10, event->getHistoricalRawX(0, 0)); - ASSERT_EQ(20, event->getHistoricalRawX(1, 0)); - ASSERT_EQ(110, event->getHistoricalRawX(0, 1)); - ASSERT_EQ(120, event->getHistoricalRawX(1, 1)); - ASSERT_EQ(210, event->getRawX(0)); - ASSERT_EQ(220, event->getRawX(1)); - - ASSERT_EQ(11, event->getHistoricalRawY(0, 0)); - ASSERT_EQ(21, event->getHistoricalRawY(1, 0)); - ASSERT_EQ(111, event->getHistoricalRawY(0, 1)); - ASSERT_EQ(121, event->getHistoricalRawY(1, 1)); - ASSERT_EQ(211, event->getRawY(0)); - ASSERT_EQ(221, event->getRawY(1)); + ASSERT_EQ(11, event->getHistoricalRawPointerCoords(0, 0)->getAxisValue(AMOTION_EVENT_AXIS_Y)); + ASSERT_EQ(21, event->getHistoricalRawPointerCoords(1, 0)->getAxisValue(AMOTION_EVENT_AXIS_Y)); + ASSERT_EQ(111, event->getHistoricalRawPointerCoords(0, 1)->getAxisValue(AMOTION_EVENT_AXIS_Y)); + ASSERT_EQ(121, event->getHistoricalRawPointerCoords(1, 1)->getAxisValue(AMOTION_EVENT_AXIS_Y)); + ASSERT_EQ(211, event->getRawPointerCoords(0)->getAxisValue(AMOTION_EVENT_AXIS_Y)); + ASSERT_EQ(221, event->getRawPointerCoords(1)->getAxisValue(AMOTION_EVENT_AXIS_Y)); + + ASSERT_EQ(RAW_Y_OFFSET + 11 * RAW_Y_SCALE, + event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0)); + ASSERT_EQ(RAW_Y_OFFSET + 21 * RAW_Y_SCALE, + event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0)); + ASSERT_EQ(RAW_Y_OFFSET + 111 * RAW_Y_SCALE, + event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1)); + ASSERT_EQ(RAW_Y_OFFSET + 121 * RAW_Y_SCALE, + event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1)); + ASSERT_EQ(RAW_Y_OFFSET + 211 * RAW_Y_SCALE, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0)); + ASSERT_EQ(RAW_Y_OFFSET + 221 * RAW_Y_SCALE, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1)); + + ASSERT_EQ(RAW_X_OFFSET + 10 * RAW_X_SCALE, event->getHistoricalRawX(0, 0)); + ASSERT_EQ(RAW_X_OFFSET + 20 * RAW_X_SCALE, event->getHistoricalRawX(1, 0)); + ASSERT_EQ(RAW_X_OFFSET + 110 * RAW_X_SCALE, event->getHistoricalRawX(0, 1)); + ASSERT_EQ(RAW_X_OFFSET + 120 * RAW_X_SCALE, event->getHistoricalRawX(1, 1)); + ASSERT_EQ(RAW_X_OFFSET + 210 * RAW_X_SCALE, event->getRawX(0)); + ASSERT_EQ(RAW_X_OFFSET + 220 * RAW_X_SCALE, event->getRawX(1)); + + ASSERT_EQ(RAW_Y_OFFSET + 11 * RAW_Y_SCALE, event->getHistoricalRawY(0, 0)); + ASSERT_EQ(RAW_Y_OFFSET + 21 * RAW_Y_SCALE, event->getHistoricalRawY(1, 0)); + ASSERT_EQ(RAW_Y_OFFSET + 111 * RAW_Y_SCALE, event->getHistoricalRawY(0, 1)); + ASSERT_EQ(RAW_Y_OFFSET + 121 * RAW_Y_SCALE, event->getHistoricalRawY(1, 1)); + ASSERT_EQ(RAW_Y_OFFSET + 211 * RAW_Y_SCALE, event->getRawY(0)); + ASSERT_EQ(RAW_Y_OFFSET + 221 * RAW_Y_SCALE, event->getRawY(1)); ASSERT_EQ(X_OFFSET + 10 * X_SCALE, event->getHistoricalX(0, 0)); ASSERT_EQ(X_OFFSET + 20 * X_SCALE, event->getHistoricalX(1, 0)); @@ -543,8 +546,8 @@ TEST_F(MotionEventTest, Scale) { ASSERT_EQ(X_OFFSET * 2, event.getXOffset()); ASSERT_EQ(Y_OFFSET * 2, event.getYOffset()); - ASSERT_EQ(210 * 2, event.getRawX(0)); - ASSERT_EQ(211 * 2, event.getRawY(0)); + ASSERT_EQ((RAW_X_OFFSET + 210 * RAW_X_SCALE) * 2, event.getRawX(0)); + ASSERT_EQ((RAW_Y_OFFSET + 211 * RAW_Y_SCALE) * 2, event.getRawY(0)); ASSERT_EQ((X_OFFSET + 210 * X_SCALE) * 2, event.getX(0)); ASSERT_EQ((Y_OFFSET + 211 * Y_SCALE) * 2, event.getY(0)); ASSERT_EQ(212, event.getPressure(0)); @@ -592,10 +595,10 @@ TEST_F(MotionEventTest, Transform) { // The geometrical representation is irrelevant to the test, it's just easy to generate // and check rotation. We set the orientation to the same angle. // Coordinate system: down is increasing Y, right is increasing X. - const float PI_180 = float(M_PI / 180); - const float RADIUS = 10; - const float ARC = 36; - const float ROTATION = ARC * 2; + static constexpr float PI_180 = float(M_PI / 180); + static constexpr float RADIUS = 10; + static constexpr float ARC = 36; + static constexpr float ROTATION = ARC * 2; const size_t pointerCount = 11; PointerProperties pointerProperties[pointerCount]; @@ -616,9 +619,8 @@ TEST_F(MotionEventTest, Transform) { AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, identityTransform, 0 /*xPrecision*/, 0 /*yPrecision*/, 3 + RADIUS /*xCursorPosition*/, 2 /*yCursorPosition*/, - ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, - 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, - pointerCoords); + identityTransform, 0 /*downTime*/, 0 /*eventTime*/, pointerCount, + pointerProperties, pointerCoords); float originalRawX = 0 + 3; float originalRawY = -RADIUS + 2; @@ -661,7 +663,7 @@ TEST_F(MotionEventTest, Transform) { MotionEvent createTouchDownEvent(float x, float y, float dx, float dy, const ui::Transform& transform, - uint32_t displayOrientation = ui::Transform::ROT_0) { + const ui::Transform& rawTransform) { std::vector pointerProperties; pointerProperties.push_back(PointerProperties{/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER}); std::vector pointerCoords; @@ -677,19 +679,18 @@ MotionEvent createTouchDownEvent(float x, float y, float dx, float dy, /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, transform, /* xPrecision */ 0, /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, displayOrientation, - /* displayWidth */ 400, - /* displayHeight */ 800, eventTime, eventTime, pointerCoords.size(), - pointerProperties.data(), pointerCoords.data()); + AMOTION_EVENT_INVALID_CURSOR_POSITION, rawTransform, eventTime, eventTime, + pointerCoords.size(), pointerProperties.data(), pointerCoords.data()); return event; } TEST_F(MotionEventTest, ApplyTransform) { // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). ui::Transform identity; - ui::Transform xform(ui::Transform::ROT_90, 800, 400); - xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90); + ui::Transform transform(ui::Transform::ROT_90, 800, 400); + transform.set(transform.tx() + 20, transform.ty() + 40); + ui::Transform rawTransform(ui::Transform::ROT_90, 800, 400); + MotionEvent event = createTouchDownEvent(60, 100, 42, 96, transform, rawTransform); ASSERT_EQ(700, event.getRawX(0)); ASSERT_EQ(60, event.getRawY(0)); ASSERT_NE(event.getRawX(0), event.getX(0)); @@ -698,10 +699,10 @@ TEST_F(MotionEventTest, ApplyTransform) { ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); - MotionEvent changedEvent = createTouchDownEvent(60, 100, 42, 96, identity); - const std::array rowMajor{xform[0][0], xform[1][0], xform[2][0], - xform[0][1], xform[1][1], xform[2][1], - xform[0][2], xform[1][2], xform[2][2]}; + MotionEvent changedEvent = createTouchDownEvent(60, 100, 42, 96, identity, identity); + const std::array rowMajor{transform[0][0], transform[1][0], transform[2][0], + transform[0][1], transform[1][1], transform[2][1], + transform[0][2], transform[1][2], transform[2][2]}; changedEvent.applyTransform(rowMajor); // transformContent effectively rotates the raw coordinates, so those should now include @@ -727,9 +728,9 @@ TEST_F(MotionEventTest, NonPointerSourcesAreNotTranslated) { AINPUT_SOURCE_JOYSTICK}; for (uint32_t source : NON_POINTER_SOURCES) { // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). - ui::Transform xform(ui::Transform::ROT_90, 800, 400); - xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90); + ui::Transform transform(ui::Transform::ROT_90, 800, 400); + transform.set(transform.tx() + 20, transform.ty() + 40); + MotionEvent event = createTouchDownEvent(60, 100, 42, 96, transform, transform); event.setSource(source); // Since this event comes from a non-pointer source, it should include rotation but not @@ -741,72 +742,34 @@ TEST_F(MotionEventTest, NonPointerSourcesAreNotTranslated) { } } -TEST_F(MotionEventTest, RawCompatTransform) { - { - // Make sure raw is raw regardless of transform translation. - ui::Transform xform; - xform.set(20, 40); - MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform); - ASSERT_EQ(60, event.getRawX(0)); - ASSERT_EQ(100, event.getRawY(0)); - ASSERT_NE(event.getRawX(0), event.getX(0)); - ASSERT_NE(event.getRawY(0), event.getY(0)); - // Relative values should not be modified. - ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); - ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); - } +TEST_F(MotionEventTest, AxesAreCorrectlyTransformed) { + const ui::Transform identity; + ui::Transform transform; + transform.set({1.1, -2.2, 3.3, -4.4, 5.5, -6.6, 0, 0, 1}); + ui::Transform rawTransform; + rawTransform.set({-6.6, 5.5, -4.4, 3.3, -2.2, 1.1, 0, 0, 1}); + auto transformWithoutTranslation = [](const ui::Transform& t, float x, float y) { + auto newPoint = t.transform(x, y); + auto newOrigin = t.transform(0, 0); + return newPoint - newOrigin; + }; - // Next check that getRaw contains rotation (for compatibility) but otherwise is still - // "Screen-space". The following tests check all 3 rotations. - { - // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). - ui::Transform xform(ui::Transform::ROT_90, 800, 400); - xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90); - ASSERT_EQ(700, event.getRawX(0)); - ASSERT_EQ(60, event.getRawY(0)); - ASSERT_NE(event.getRawX(0), event.getX(0)); - ASSERT_NE(event.getRawY(0), event.getY(0)); - // Relative values should be rotated but not translated. - ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); - ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); - } + const MotionEvent event = createTouchDownEvent(60, 100, 42, 96, transform, rawTransform); - { - // Same as above, but check rotate-180. - ui::Transform xform(ui::Transform::ROT_180, 400, 800); - xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_180); - ASSERT_EQ(340, event.getRawX(0)); - ASSERT_EQ(700, event.getRawY(0)); - // Relative values should be rotated but not translated. - ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); - ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); - } + // The x and y axes should have the window transform applied. + const auto newPoint = transform.transform(60, 100); + ASSERT_EQ(newPoint.x, event.getX(0)); + ASSERT_EQ(newPoint.y, event.getY(0)); - { - // Same as above, but check rotate-270. - ui::Transform xform(ui::Transform::ROT_270, 800, 400); - xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_270); - ASSERT_EQ(100, event.getRawX(0)); - ASSERT_EQ(340, event.getRawY(0)); - // Relative values should be rotated but not translated. - ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); - ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); - } + // The raw values should have the display transform applied. + const auto raw = rawTransform.transform(60, 100); + ASSERT_EQ(raw.x, event.getRawX(0)); + ASSERT_EQ(raw.y, event.getRawY(0)); - { - // Finally, check that raw isn't effected by transform - ui::Transform xform(ui::Transform::ROT_270, 800, 400); - xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90); - ASSERT_EQ(700, event.getRawX(0)); - ASSERT_EQ(60, event.getRawY(0)); - // Relative values should be rotated but not translated. - ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); - ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); - } + // Relative values should have the window transform applied without any translation. + const auto rel = transformWithoutTranslation(transform, 42, 96); + ASSERT_EQ(rel.x, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); + ASSERT_EQ(rel.y, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); } TEST_F(MotionEventTest, Initialize_SetsClassification) { @@ -832,8 +795,7 @@ TEST_F(MotionEventTest, Initialize_SetsClassification) { DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(classification, event.getClassification()); } @@ -854,9 +816,9 @@ TEST_F(MotionEventTest, Initialize_SetsCursorPosition) { event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE, identityTransform, 0, 0, - 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/, 0 /*eventTime*/, - pointerCount, pointerProperties, pointerCoords); + 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, identityTransform, + 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, + pointerCoords); event.offsetLocation(20, 60); ASSERT_EQ(280, event.getRawXCursorPosition()); ASSERT_EQ(540, event.getRawYCursorPosition()); diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index 8db5bf1289..d09f2ac748 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -160,13 +160,14 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { constexpr float yScale = 3; constexpr float xOffset = -10; constexpr float yOffset = -20; + constexpr float rawXScale = 4; + constexpr float rawYScale = -5; + constexpr float rawXOffset = -11; + constexpr float rawYOffset = 42; constexpr float xPrecision = 0.25; constexpr float yPrecision = 0.5; constexpr float xCursorPosition = 1.3; constexpr float yCursorPosition = 50.6; - constexpr uint32_t displayOrientation = ui::Transform::ROT_0; - constexpr int32_t displayWidth = 1000; - constexpr int32_t displayHeight = 2000; constexpr nsecs_t downTime = 3; constexpr size_t pointerCount = 3; constexpr nsecs_t eventTime = 4; @@ -192,12 +193,14 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { ui::Transform transform; transform.set({xScale, 0, xOffset, 0, yScale, yOffset, 0, 0, 1}); + ui::Transform rawTransform; + rawTransform.set({rawXScale, 0, rawXOffset, 0, rawYScale, rawYOffset, 0, 0, 1}); status = mPublisher->publishMotionEvent(seq, eventId, deviceId, source, displayId, hmac, action, actionButton, flags, edgeFlags, metaState, buttonState, classification, transform, xPrecision, yPrecision, - xCursorPosition, yCursorPosition, displayOrientation, - displayWidth, displayHeight, downTime, eventTime, - pointerCount, pointerProperties, pointerCoords); + xCursorPosition, yCursorPosition, rawTransform, + downTime, eventTime, pointerCount, pointerProperties, + pointerCoords); ASSERT_EQ(OK, status) << "publisher publishMotionEvent should return OK"; @@ -234,9 +237,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { EXPECT_EQ(yCursorPosition, motionEvent->getRawYCursorPosition()); EXPECT_EQ(xCursorPosition * xScale + xOffset, motionEvent->getXCursorPosition()); EXPECT_EQ(yCursorPosition * yScale + yOffset, motionEvent->getYCursorPosition()); - EXPECT_EQ(displayOrientation, motionEvent->getDisplayOrientation()); - EXPECT_EQ(displayWidth, motionEvent->getDisplaySize().x); - EXPECT_EQ(displayHeight, motionEvent->getDisplaySize().y); + EXPECT_EQ(rawTransform, motionEvent->getRawTransform()); EXPECT_EQ(downTime, motionEvent->getDownTime()); EXPECT_EQ(eventTime, motionEvent->getEventTime()); EXPECT_EQ(pointerCount, motionEvent->getPointerCount()); @@ -247,28 +248,18 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { EXPECT_EQ(pointerProperties[i].id, motionEvent->getPointerId(i)); EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), - motionEvent->getRawX(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), - motionEvent->getRawY(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X) * xScale + xOffset, - motionEvent->getX(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y) * yScale + yOffset, - motionEvent->getY(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - motionEvent->getPressure(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), - motionEvent->getSize(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - motionEvent->getTouchMajor(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - motionEvent->getTouchMinor(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - motionEvent->getToolMajor(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - motionEvent->getToolMinor(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), - motionEvent->getOrientation(i)); + const auto& pc = pointerCoords[i]; + EXPECT_EQ(pc.getX() * rawXScale + rawXOffset, motionEvent->getRawX(i)); + EXPECT_EQ(pc.getY() * rawYScale + rawYOffset, motionEvent->getRawY(i)); + EXPECT_EQ(pc.getX() * xScale + xOffset, motionEvent->getX(i)); + EXPECT_EQ(pc.getY() * yScale + yOffset, motionEvent->getY(i)); + EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), motionEvent->getPressure(i)); + EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_SIZE), motionEvent->getSize(i)); + EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), motionEvent->getTouchMajor(i)); + EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), motionEvent->getTouchMinor(i)); + EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), motionEvent->getToolMajor(i)); + EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), motionEvent->getToolMinor(i)); + EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), motionEvent->getOrientation(i)); } status = mConsumer->sendFinishedSignal(seq, false); @@ -505,12 +496,12 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenSequenceNumberIsZer } ui::Transform identityTransform; - status = mPublisher->publishMotionEvent(0, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, - 0, 0, 0, MotionClassification::NONE, identityTransform, - 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, - ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount, - pointerProperties, pointerCoords); + status = + mPublisher->publishMotionEvent(0, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, + 0, 0, 0, MotionClassification::NONE, identityTransform, + 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, + 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } @@ -522,12 +513,12 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessTha PointerCoords pointerCoords[pointerCount]; ui::Transform identityTransform; - status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, - 0, 0, 0, MotionClassification::NONE, identityTransform, - 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, - ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount, - pointerProperties, pointerCoords); + status = + mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, + 0, 0, 0, MotionClassification::NONE, identityTransform, + 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, + 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } @@ -544,12 +535,12 @@ TEST_F(InputPublisherAndConsumerTest, } ui::Transform identityTransform; - status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, - 0, 0, 0, MotionClassification::NONE, identityTransform, - 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, - ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount, - pointerProperties, pointerCoords); + status = + mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, + 0, 0, 0, MotionClassification::NONE, identityTransform, + 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, + 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp index 18289a5f11..2f88704d63 100644 --- a/libs/input/tests/StructLayout_test.cpp +++ b/libs/input/tests/StructLayout_test.cpp @@ -49,7 +49,7 @@ void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage::Body::Key, downTime, 88); CHECK_OFFSET(InputMessage::Body::Motion, eventId, 0); - CHECK_OFFSET(InputMessage::Body::Motion, empty1, 4); + CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 4); CHECK_OFFSET(InputMessage::Body::Motion, eventTime, 8); CHECK_OFFSET(InputMessage::Body::Motion, deviceId, 16); CHECK_OFFSET(InputMessage::Body::Motion, source, 20); @@ -74,11 +74,13 @@ void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 124); CHECK_OFFSET(InputMessage::Body::Motion, xCursorPosition, 128); CHECK_OFFSET(InputMessage::Body::Motion, yCursorPosition, 132); - CHECK_OFFSET(InputMessage::Body::Motion, displayOrientation, 136); - CHECK_OFFSET(InputMessage::Body::Motion, displayWidth, 140); - CHECK_OFFSET(InputMessage::Body::Motion, displayHeight, 144); - CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 148); - CHECK_OFFSET(InputMessage::Body::Motion, pointers, 152); + CHECK_OFFSET(InputMessage::Body::Motion, dsdxRaw, 136); + CHECK_OFFSET(InputMessage::Body::Motion, dtdxRaw, 140); + CHECK_OFFSET(InputMessage::Body::Motion, dtdyRaw, 144); + CHECK_OFFSET(InputMessage::Body::Motion, dsdyRaw, 148); + CHECK_OFFSET(InputMessage::Body::Motion, txRaw, 152); + CHECK_OFFSET(InputMessage::Body::Motion, tyRaw, 156); + CHECK_OFFSET(InputMessage::Body::Motion, pointers, 160); CHECK_OFFSET(InputMessage::Body::Focus, eventId, 0); CHECK_OFFSET(InputMessage::Body::Focus, hasFocus, 4); diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp index 13e2b02ca4..3039362c2b 100644 --- a/libs/input/tests/VelocityTracker_test.cpp +++ b/libs/input/tests/VelocityTracker_test.cpp @@ -184,8 +184,7 @@ static std::vector createMotionEventStream( AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, identityTransform, 0 /*xPrecision*/, 0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, 0 /*downTime*/, entry.eventTime.count(), pointerCount, properties, coords); events.emplace_back(event); diff --git a/libs/input/tests/VerifiedInputEvent_test.cpp b/libs/input/tests/VerifiedInputEvent_test.cpp index b29c9a4877..f2b59ea9ab 100644 --- a/libs/input/tests/VerifiedInputEvent_test.cpp +++ b/libs/input/tests/VerifiedInputEvent_test.cpp @@ -43,12 +43,12 @@ static MotionEvent getMotionEventWithFlags(int32_t flags) { ui::Transform transform; transform.set({2, 0, 4, 0, 3, 5, 0, 0, 1}); + ui::Transform identity; event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_DEFAULT, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, transform, 0.1 /*xPrecision*/, 0.2 /*yPrecision*/, - 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 100 /*downTime*/, + 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, identity, 100 /*downTime*/, 200 /*eventTime*/, pointerCount, pointerProperties, pointerCoords); return event; } diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index 6ce0313929..68d25f9ec7 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -236,8 +236,8 @@ static MotionEvent generateMotionEvent() { /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, identityTransform, /* xPrecision */ 0, /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, currentTime, currentTime, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, currentTime, + currentTime, /*pointerCount*/ 1, pointerProperties, pointerCoords); return event; } diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index 571c126658..bcb00719cd 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -309,15 +309,14 @@ std::string SensorEntry::getDescription() const { volatile int32_t DispatchEntry::sNextSeqAtomic; DispatchEntry::DispatchEntry(std::shared_ptr eventEntry, int32_t targetFlags, - ui::Transform transform, float globalScaleFactor, - uint32_t displayOrientation, int2 displaySize) + const ui::Transform& transform, const ui::Transform& rawTransform, + float globalScaleFactor) : seq(nextSeq()), eventEntry(std::move(eventEntry)), targetFlags(targetFlags), transform(transform), + rawTransform(rawTransform), globalScaleFactor(globalScaleFactor), - displayOrientation(displayOrientation), - displaySize(displaySize), deliveryTime(0), resolvedAction(0), resolvedFlags(0) {} diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index 5365a78b0a..7a121ce798 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -226,9 +226,8 @@ struct DispatchEntry { std::shared_ptr eventEntry; // the event to dispatch int32_t targetFlags; ui::Transform transform; + ui::Transform rawTransform; float globalScaleFactor; - uint32_t displayOrientation; - int2 displaySize; // Both deliveryTime and timeoutTime are only populated when the entry is sent to the app, // and will be undefined before that. nsecs_t deliveryTime; // time when the event was actually delivered @@ -241,8 +240,8 @@ struct DispatchEntry { int32_t resolvedFlags; DispatchEntry(std::shared_ptr eventEntry, int32_t targetFlags, - ui::Transform transform, float globalScaleFactor, uint32_t displayOrientation, - int2 displaySize); + const ui::Transform& transform, const ui::Transform& rawTransform, + float globalScaleFactor); inline bool hasForegroundTarget() const { return targetFlags & InputTarget::FLAG_FOREGROUND; } diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index da3e237e3e..22d2e9a97e 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -346,18 +346,15 @@ std::unique_ptr createDispatchEntry(const InputTarget& inputTarge // Use identity transform for joystick and position-based (touchpad) events because they // don't depend on the window transform. return std::make_unique(eventEntry, inputTargetFlags, identityTransform, - 1.0f /*globalScaleFactor*/, - inputTarget.displayOrientation, - inputTarget.displaySize); + identityTransform, 1.0f /*globalScaleFactor*/); } } if (inputTarget.useDefaultPointerTransform()) { const ui::Transform& transform = inputTarget.getDefaultPointerTransform(); return std::make_unique(eventEntry, inputTargetFlags, transform, - inputTarget.globalScaleFactor, - inputTarget.displayOrientation, - inputTarget.displaySize); + inputTarget.displayTransform, + inputTarget.globalScaleFactor); } ALOG_ASSERT(eventEntry->type == EventEntry::Type::MOTION); @@ -408,9 +405,8 @@ std::unique_ptr createDispatchEntry(const InputTarget& inputTarge std::unique_ptr dispatchEntry = std::make_unique(std::move(combinedMotionEntry), inputTargetFlags, - firstPointerTransform, inputTarget.globalScaleFactor, - inputTarget.displayOrientation, - inputTarget.displaySize); + firstPointerTransform, inputTarget.displayTransform, + inputTarget.globalScaleFactor); return dispatchEntry; } @@ -2347,7 +2343,7 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( for (const TouchedMonitor& touchedMonitor : tempTouchState.gestureMonitors) { addMonitoringTargetLocked(touchedMonitor.monitor, touchedMonitor.xOffset, - touchedMonitor.yOffset, inputTargets); + touchedMonitor.yOffset, displayId, inputTargets); } // Drop the outside or hover touch windows since we will not care about them @@ -2526,9 +2522,7 @@ void InputDispatcher::addWindowTargetLocked(const sp& windowHa inputTarget.globalScaleFactor = windowInfo->globalScaleFactor; const auto& displayInfoIt = mDisplayInfos.find(windowInfo->displayId); if (displayInfoIt != mDisplayInfos.end()) { - const auto& displayInfo = displayInfoIt->second; - inputTarget.displayOrientation = displayInfo.transform.getOrientation(); - inputTarget.displaySize = int2(displayInfo.logicalWidth, displayInfo.logicalHeight); + inputTarget.displayTransform = displayInfoIt->second.transform; } else { ALOGI_IF(isPerWindowInputRotationEnabled(), "DisplayInfo not found for window on display: %d", windowInfo->displayId); @@ -2552,19 +2546,38 @@ void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector& if (it != mGlobalMonitorsByDisplay.end()) { const std::vector& monitors = it->second; for (const Monitor& monitor : monitors) { - addMonitoringTargetLocked(monitor, xOffset, yOffset, inputTargets); + addMonitoringTargetLocked(monitor, xOffset, yOffset, displayId, inputTargets); } } } void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, float xOffset, - float yOffset, + float yOffset, int32_t displayId, std::vector& inputTargets) { InputTarget target; target.inputChannel = monitor.inputChannel; target.flags = InputTarget::FLAG_DISPATCH_AS_IS; - ui::Transform t; - t.set(xOffset, yOffset); + ui::Transform t = ui::Transform(xOffset, yOffset); + if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) { + // Input monitors always get un-rotated display coordinates. We undo the display + // rotation that is present in the display transform so that display rotation is not + // applied to these input targets. + const auto& displayInfo = it->second; + int32_t width = displayInfo.logicalWidth; + int32_t height = displayInfo.logicalHeight; + const auto orientation = displayInfo.transform.getOrientation(); + uint32_t inverseOrientation = orientation; + if (orientation == ui::Transform::ROT_90) { + inverseOrientation = ui::Transform::ROT_270; + std::swap(width, height); + } else if (orientation == ui::Transform::ROT_270) { + inverseOrientation = ui::Transform::ROT_90; + std::swap(width, height); + } + target.displayTransform = + ui::Transform(inverseOrientation, width, height) * displayInfo.transform; + t = t * target.displayTransform; + } target.setDefaultPointerTransform(t); inputTargets.push_back(target); } @@ -3250,9 +3263,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, motionEntry.xPrecision, motionEntry.yPrecision, motionEntry.xCursorPosition, motionEntry.yCursorPosition, - dispatchEntry->displayOrientation, - dispatchEntry->displaySize.x, - dispatchEntry->displaySize.y, + dispatchEntry->rawTransform, motionEntry.downTime, motionEntry.eventTime, motionEntry.pointerCount, motionEntry.pointerProperties, usingCoords); @@ -3981,14 +3992,14 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { mLock.unlock(); MotionEvent event; - ui::Transform transform; + ui::Transform identityTransform; event.initialize(args->id, args->deviceId, args->source, args->displayId, INVALID_HMAC, args->action, args->actionButton, args->flags, args->edgeFlags, - args->metaState, args->buttonState, args->classification, transform, - args->xPrecision, args->yPrecision, args->xCursorPosition, - args->yCursorPosition, ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, - INVALID_DISPLAY_SIZE, args->downTime, args->eventTime, - args->pointerCount, args->pointerProperties, args->pointerCoords); + args->metaState, args->buttonState, args->classification, + identityTransform, args->xPrecision, args->yPrecision, + args->xCursorPosition, args->yCursorPosition, identityTransform, + args->downTime, args->eventTime, args->pointerCount, + args->pointerProperties, args->pointerCoords); policyFlags |= POLICY_FLAG_FILTERED; if (!mPolicy->filterInputEvent(&event, policyFlags)) { diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 4f6d0d2759..e9fe2810d1 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -525,7 +525,8 @@ private: int32_t targetFlags, BitSet32 pointerIds, std::vector& inputTargets) REQUIRES(mLock); void addMonitoringTargetLocked(const Monitor& monitor, float xOffset, float yOffset, - std::vector& inputTargets) REQUIRES(mLock); + int32_t displayId, std::vector& inputTargets) + REQUIRES(mLock); void addGlobalMonitoringTargetsLocked(std::vector& inputTargets, int32_t displayId, float xOffset = 0, float yOffset = 0) REQUIRES(mLock); void pokeUserActivityLocked(const EventEntry& eventEntry) REQUIRES(mLock); diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h index 7c463c8697..5b76eee343 100644 --- a/services/inputflinger/dispatcher/InputTarget.h +++ b/services/inputflinger/dispatcher/InputTarget.h @@ -101,11 +101,8 @@ struct InputTarget { // (ignored for KeyEvents) float globalScaleFactor = 1.0f; - // Current display orientation - uint32_t displayOrientation = ui::Transform::ROT_0; - - // Display-size in its natural rotation. Used for compatibility transform of raw coordinates. - int2 displaySize = {INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE}; + // Current display transform. Used for compatibility for raw coordinates. + ui::Transform displayTransform; // The subset of pointer ids to include in motion events dispatched to this input target // if FLAG_SPLIT is set. diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 903f337eb9..e9d45b22ad 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -542,8 +542,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, + ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -556,8 +556,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, - ARBITRARY_TIME, ARBITRARY_TIME, + identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -569,8 +568,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, - ARBITRARY_TIME, ARBITRARY_TIME, + identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -583,8 +581,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, - ARBITRARY_TIME, ARBITRARY_TIME, + identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -596,8 +593,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, - ARBITRARY_TIME, ARBITRARY_TIME, + identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -608,8 +604,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, + ARBITRARY_TIME, /*pointerCount*/ 0, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -619,8 +615,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, + ARBITRARY_TIME, /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -632,8 +628,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, + ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -644,8 +640,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, + ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -658,8 +654,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, + ARBITRARY_TIME, /*pointerCount*/ 2, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -1296,9 +1292,8 @@ public: mAction, mActionButton, mFlags, /* edgeFlags */ 0, AMETA_NONE, mButtonState, MotionClassification::NONE, identityTransform, /* xPrecision */ 0, /* yPrecision */ 0, mRawXCursorPosition, - mRawYCursorPosition, mDisplayOrientation, mDisplayWidth, mDisplayHeight, - mEventTime, mEventTime, mPointers.size(), pointerProperties.data(), - pointerCoords.data()); + mRawYCursorPosition, identityTransform, mEventTime, mEventTime, + mPointers.size(), pointerProperties.data(), pointerCoords.data()); return event; } @@ -1313,9 +1308,6 @@ private: int32_t mFlags{0}; float mRawXCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION}; float mRawYCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION}; - uint32_t mDisplayOrientation{ui::Transform::ROT_0}; - int32_t mDisplayWidth{INVALID_DISPLAY_SIZE}; - int32_t mDisplayHeight{INVALID_DISPLAY_SIZE}; std::vector mPointers; }; @@ -3622,8 +3614,7 @@ protected: DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - 0 /*INVALID_DISPLAY_SIZE*/, 0 /*INVALID_DISPLAY_SIZE*/, eventTime, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, eventTime, eventTime, /*pointerCount*/ 1, pointerProperties, pointerCoords); -- cgit v1.2.3-59-g8ed1b From 9cf4a4d4e57d059a4e4119f0a8f2a8be237f28c2 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 17 Sep 2021 12:16:08 -0700 Subject: SurfaceControl: Add setDropInputMode api Introduces an API to drop input events on this SurfaceControl. This policy will be inherited by its children. The caller must hold the ACCESS_SURFACE_FLINGER permission. Options include: ALL: SurfaceControl and its children will not receive any input regardless of whether it has a valid input channel. OBSCURED: SurfaceControl and its children will not receive any input if the layer is obscured, cropped by its parent or translucent. These policies are used to enable features that allow for a less trusted interaction model between apps. See the bug for more details. Test: atest libgui_test InputDispatcherDropInputFeatureTest Bug:197364677 Change-Id: I443741d5ab51a45d37fb865f11c433c436d96c1e --- libs/gui/Android.bp | 1 + libs/gui/LayerState.cpp | 12 +++++++- libs/gui/SurfaceComposerClient.cpp | 15 ++++++++++ libs/gui/android/gui/DropInputMode.aidl | 45 ++++++++++++++++++++++++++++ libs/gui/include/gui/LayerState.h | 5 ++++ libs/gui/include/gui/SurfaceComposerClient.h | 1 + services/surfaceflinger/Layer.cpp | 9 ++++++ services/surfaceflinger/Layer.h | 5 ++++ services/surfaceflinger/SurfaceFlinger.cpp | 10 +++++++ 9 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 libs/gui/android/gui/DropInputMode.aidl diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 2d1f5a1694..8c359c7756 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -55,6 +55,7 @@ cc_library_headers { filegroup { name: "guiconstants_aidl", srcs: [ + "android/gui/DropInputMode.aidl", "android/**/TouchOcclusionMode.aidl", ], } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 1fd9d13902..a419a63056 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -69,7 +69,8 @@ layer_state_t::layer_state_t() isTrustedOverlay(false), bufferCrop(Rect::INVALID_RECT), destinationFrame(Rect::INVALID_RECT), - releaseBufferListener(nullptr) { + releaseBufferListener(nullptr), + dropInputMode(gui::DropInputMode::NONE) { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; hdrMetadata.validTypes = 0; @@ -174,6 +175,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeBool, isTrustedOverlay); SAFE_PARCEL(output.writeStrongBinder, releaseBufferEndpoint); + SAFE_PARCEL(output.writeUint32, static_cast(dropInputMode)); return NO_ERROR; } @@ -304,6 +306,10 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readBool, &isTrustedOverlay); SAFE_PARCEL(input.readNullableStrongBinder, &releaseBufferEndpoint); + + uint32_t mode; + SAFE_PARCEL(input.readUint32, &mode); + dropInputMode = static_cast(mode); return NO_ERROR; } @@ -558,6 +564,10 @@ void layer_state_t::merge(const layer_state_t& other) { if (other.what & eProducerDisconnect) { what |= eProducerDisconnect; } + if (other.what & eDropInputModeChanged) { + what |= eDropInputModeChanged; + dropInputMode = other.dropInputMode; + } if ((other.what & what) != other.what) { ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? " "other.what=0x%" PRIX64 " what=0x%" PRIX64 " unmerged flags=0x%" PRIX64, diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 1bca6f9167..64361db41e 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1739,6 +1739,21 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDesti return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDropInputMode( + const sp& sc, gui::DropInputMode mode) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::eDropInputModeChanged; + s->dropInputMode = mode; + + registerSurfaceControlForCallback(sc); + return *this; +} + // --------------------------------------------------------------------------- DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp& token) { diff --git a/libs/gui/android/gui/DropInputMode.aidl b/libs/gui/android/gui/DropInputMode.aidl new file mode 100644 index 0000000000..2b31744ca2 --- /dev/null +++ b/libs/gui/android/gui/DropInputMode.aidl @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2021, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.gui; + + +/** + * Input event drop modes: Input event drop options for windows and its children. + * + * @hide + */ +@Backing(type="int") +enum DropInputMode { + /** + * Default mode, input events are sent to the target as usual. + */ + NONE, + + /** + * Window and its children will not receive any input even if it has a valid input channel. + * Touches and keys will be dropped. If a window is focused, it will remain focused but will + * not receive any keys. If the window has a touchable region and is the target of an input + * event, the event will be dropped and will not go to the window behind. ref: b/197296414 + */ + ALL, + + /** + * Similar to DROP but input events are only dropped if the window is considered to be + * obscured. ref: b/197364677 + */ + OBSCURED +} diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index f14127c9de..b27102bcce 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -118,6 +119,7 @@ struct layer_state_t { eAutoRefreshChanged = 0x1000'00000000, eStretchChanged = 0x2000'00000000, eTrustedOverlayChanged = 0x4000'00000000, + eDropInputModeChanged = 0x8000'00000000, }; layer_state_t(); @@ -248,6 +250,9 @@ struct layer_state_t { // releaseCallbackId and release fence to all listeners so we store which listener the setBuffer // was called with. sp releaseBufferEndpoint; + + // Force inputflinger to drop all input events for the layer and its children. + gui::DropInputMode dropInputMode; }; struct ComposerState { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index baa6878414..ffd0244275 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -562,6 +562,7 @@ public: Transaction& setBufferCrop(const sp& sc, const Rect& bufferCrop); Transaction& setDestinationFrame(const sp& sc, const Rect& destinationFrame); + Transaction& setDropInputMode(const sp& sc, gui::DropInputMode mode); status_t setDisplaySurface(const sp& token, const sp& bufferProducer); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index ef6f115fdc..d549fe9966 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -135,6 +135,7 @@ Layer::Layer(const LayerCreationArgs& args) mDrawingState.postTime = -1; mDrawingState.destinationFrame.makeInvalid(); mDrawingState.isTrustedOverlay = false; + mDrawingState.dropInputMode = gui::DropInputMode::NONE; if (args.flags & ISurfaceComposerClient::eNoColorFill) { // Set an invalid color so there is no color fill. @@ -2541,6 +2542,14 @@ wp Layer::fromHandle(const sp& handleBinder) { return handle->owner; } +bool Layer::setDropInputMode(gui::DropInputMode mode) { + if (mDrawingState.dropInputMode == mode) { + return false; + } + mDrawingState.dropInputMode = mode; + return true; +} + // --------------------------------------------------------------------------- std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 3c3c7d0b88..b70d5d474c 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -17,6 +17,7 @@ #pragma once +#include #include #include #include @@ -277,6 +278,8 @@ public: Rect destinationFrame; sp releaseBufferEndpoint; + + gui::DropInputMode dropInputMode; }; /* @@ -442,6 +445,8 @@ public: virtual bool setFrameRateSelectionPriority(int32_t priority); virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint); virtual void setAutoRefresh(bool /* autoRefresh */) {} + bool setDropInputMode(gui::DropInputMode); + // If the variable is not set on the layer, it traverses up the tree to inherit the frame // rate priority from its parent. virtual int32_t getFrameRateSelectionPriority() const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5a881a3dfe..5aa0b87e22 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4147,6 +4147,16 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTraversalNeeded; } } + if (what & layer_state_t::eDropInputModeChanged) { + if (privileged) { + if (layer->setDropInputMode(s.dropInputMode)) { + flags |= eTraversalNeeded; + mInputInfoChanged = true; + } + } else { + ALOGE("Attempt to update DropInputMode without permission ACCESS_SURFACE_FLINGER"); + } + } // This has to happen after we reparent children because when we reparent to null we remove // child layers from current state and remove its relative z. If the children are reparented in // the same transaction, then we have to make sure we reparent the children first so we do not -- cgit v1.2.3-59-g8ed1b From e3ce49da3f975eb9d9f516e460b83f1bdec188d6 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 29 Sep 2020 19:08:13 -0500 Subject: Remove some clang warnings Fix some clang warnings: 1. Unused variable (use constexpr instead of #define) 2. -Wextra warnings 3. Remove unused import Bug: 167947340 Test: compile and observe warnings Change-Id: Ie4a7bb1aad30f0e6556d23621ec6268185bec536 --- services/inputflinger/InputManager.h | 1 - services/inputflinger/reader/Macros.h | 2 +- .../reader/mapper/MultiTouchInputMapper.cpp | 30 +++++++++++----------- services/surfaceflinger/BufferQueueLayer.cpp | 7 +++-- 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h index 4c07c22154..f053568143 100644 --- a/services/inputflinger/InputManager.h +++ b/services/inputflinger/InputManager.h @@ -30,7 +30,6 @@ #include ::Type>::value, - Return>::type; - -// Safely cast between std::vectors of matching enum/integer/wraper types. -// Normally this is not possible with pendantic compiler type checks. However, -// given the same size, alignment, and underlying type this is safe due to -// allocator requirements and array-like element access guarantees. -template -EnableIfSafeCast*> VectorCast(std::vector* in) { - return reinterpret_cast*>(in); -} - -// Translator classes that wrap specific HWC types to make translating -// between different types (especially enum class) in code cleaner. - -// Base type for the enum wrappers below. This type provides type definitions -// and implicit conversion logic common to each wrapper type. -template -struct Wrapper { - // Alias type of this instantiantion of Wrapper. Useful for inheriting - // constructors in subclasses via "using Base::Base;" statements. - using Base = Wrapper; - - // The enum type wrapped by this instantiation of Wrapper. - using BaseType = EnumType; - - // The underlying type of the base enum type. - using ValueType = typename UnderlyingType::Type; - - // A default constructor is not defined here. Subclasses should define one - // as appropriate to define the correct inital value for the enum type. - - // Default copy constructor. - Wrapper(const Wrapper&) = default; - - // Implicit conversion from ValueType. - // NOLINTNEXTLINE(google-explicit-constructor) - Wrapper(ValueType value) : value(value) {} - - // Implicit conversion from BaseType. - // NOLINTNEXTLINE(google-explicit-constructor) - Wrapper(BaseType value) : value(static_cast(value)) {} - - // Implicit conversion from an enum type of the same underlying type. - template > - // NOLINTNEXTLINE(google-explicit-constructor) - Wrapper(const T& value) : value(static_cast(value)) {} - - // Implicit conversion to BaseType. - // NOLINTNEXTLINE(google-explicit-constructor) - operator BaseType() const { return static_cast(value); } - - // Implicit conversion to ValueType. - // NOLINTNEXTLINE(google-explicit-constructor) - operator ValueType() const { return value; } - - template > - T cast() const { - return static_cast(value); - } - - // Converts to string using HWC2 stringification of BaseType. - std::string to_string() const { - return HWC2::to_string(static_cast(value)); - } - - bool operator!=(const Wrapper& other) const { return value != other.value; } - bool operator!=(ValueType other_value) const { return value != other_value; } - bool operator!=(BaseType other_value) const { - return static_cast(value) != other_value; - } - bool operator==(const Wrapper& other) const { return value == other.value; } - bool operator==(ValueType other_value) const { return value == other_value; } - bool operator==(BaseType other_value) const { - return static_cast(value) == other_value; - } - - ValueType value; -}; - -struct Attribute final : public Wrapper { - enum : ValueType { - Invalid = HWC2_ATTRIBUTE_INVALID, - Width = HWC2_ATTRIBUTE_WIDTH, - Height = HWC2_ATTRIBUTE_HEIGHT, - VsyncPeriod = HWC2_ATTRIBUTE_VSYNC_PERIOD, - DpiX = HWC2_ATTRIBUTE_DPI_X, - DpiY = HWC2_ATTRIBUTE_DPI_Y, - }; - - Attribute() : Base(Invalid) {} - using Base::Base; -}; - -struct BlendMode final : public Wrapper { - enum : ValueType { - Invalid = HWC2_BLEND_MODE_INVALID, - None = HWC2_BLEND_MODE_NONE, - Premultiplied = HWC2_BLEND_MODE_PREMULTIPLIED, - Coverage = HWC2_BLEND_MODE_COVERAGE, - }; - - BlendMode() : Base(Invalid) {} - using Base::Base; -}; - -struct Composition final : public Wrapper { - enum : ValueType { - Invalid = HWC2_COMPOSITION_INVALID, - Client = HWC2_COMPOSITION_CLIENT, - Device = HWC2_COMPOSITION_DEVICE, - SolidColor = HWC2_COMPOSITION_SOLID_COLOR, - Cursor = HWC2_COMPOSITION_CURSOR, - Sideband = HWC2_COMPOSITION_SIDEBAND, - }; - - Composition() : Base(Invalid) {} - using Base::Base; -}; - -struct DisplayType final : public Wrapper { - enum : ValueType { - Invalid = HWC2_DISPLAY_TYPE_INVALID, - Physical = HWC2_DISPLAY_TYPE_PHYSICAL, - Virtual = HWC2_DISPLAY_TYPE_VIRTUAL, - }; - - DisplayType() : Base(Invalid) {} - using Base::Base; -}; - -struct Error final : public Wrapper { - enum : ValueType { - None = HWC2_ERROR_NONE, - BadConfig = HWC2_ERROR_BAD_CONFIG, - BadDisplay = HWC2_ERROR_BAD_DISPLAY, - BadLayer = HWC2_ERROR_BAD_LAYER, - BadParameter = HWC2_ERROR_BAD_PARAMETER, - HasChanges = HWC2_ERROR_HAS_CHANGES, - NoResources = HWC2_ERROR_NO_RESOURCES, - NotValidated = HWC2_ERROR_NOT_VALIDATED, - Unsupported = HWC2_ERROR_UNSUPPORTED, - }; - - Error() : Base(None) {} - using Base::Base; -}; - -struct LayerRequest final : public Wrapper { - enum : ValueType { - ClearClientTarget = HWC2_LAYER_REQUEST_CLEAR_CLIENT_TARGET, - }; - - LayerRequest() : Base(0) {} - using Base::Base; -}; - -struct PowerMode final : public Wrapper { - enum : ValueType { - Off = HWC2_POWER_MODE_OFF, - DozeSuspend = HWC2_POWER_MODE_DOZE_SUSPEND, - Doze = HWC2_POWER_MODE_DOZE, - On = HWC2_POWER_MODE_ON, - }; - - PowerMode() : Base(Off) {} - using Base::Base; -}; - -struct Transform final : public Wrapper { - enum : ValueType { - None = 0, - FlipH = HWC_TRANSFORM_FLIP_H, - FlipV = HWC_TRANSFORM_FLIP_V, - Rotate90 = HWC_TRANSFORM_ROT_90, - Rotate180 = HWC_TRANSFORM_ROT_180, - Rotate270 = HWC_TRANSFORM_ROT_270, - FlipHRotate90 = HWC_TRANSFORM_FLIP_H_ROT_90, - FlipVRotate90 = HWC_TRANSFORM_FLIP_V_ROT_90, - }; - - Transform() : Base(None) {} - using Base::Base; -}; - -struct Vsync final : public Wrapper { - enum : ValueType { - Invalid = HWC2_VSYNC_INVALID, - Enable = HWC2_VSYNC_ENABLE, - Disable = HWC2_VSYNC_DISABLE, - }; - - Vsync() : Base(Invalid) {} - using Base::Base; -}; - -// Utility color type. -struct Color final { - Color(const Color&) = default; - Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) : r(r), g(g), b(b), a(a) {} - // NOLINTNEXTLINE(google-explicit-constructor) - Color(hwc_color_t color) : r(color.r), g(color.g), b(color.b), a(color.a) {} - - // NOLINTNEXTLINE(google-explicit-constructor) - operator hwc_color_t() const { return {r, g, b, a}; } - - uint8_t r __attribute__((aligned(1))); - uint8_t g __attribute__((aligned(1))); - uint8_t b __attribute__((aligned(1))); - uint8_t a __attribute__((aligned(1))); -}; - -// Utility rectangle type. -struct Rect final { - // TODO(eieio): Implicit conversion to/from Android rect types. - - int32_t left __attribute__((aligned(4))); - int32_t top __attribute__((aligned(4))); - int32_t right __attribute__((aligned(4))); - int32_t bottom __attribute__((aligned(4))); -}; - -} // namespace HWC - -#endif // ANDROID_LIBVRFLINGER_HWCTYPES_H diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h deleted file mode 100644 index ae52076f99..0000000000 --- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef ANDROID_DVR_VR_FLINGER_H_ -#define ANDROID_DVR_VR_FLINGER_H_ - -#include -#include - -#define HWC2_INCLUDE_STRINGIFICATION -#define HWC2_USE_CPP11 -#include -#undef HWC2_INCLUDE_STRINGIFICATION -#undef HWC2_USE_CPP11 - -#include -#include - -namespace android { - -namespace Hwc2 { -class Composer; -} // namespace Hwc2 - -namespace dvr { - -class DisplayService; - -class VrFlinger { - public: - using RequestDisplayCallback = std::function; - static std::unique_ptr Create( - Hwc2::Composer* hidl, - hwc2_display_t primary_display_id, - RequestDisplayCallback request_display_callback); - ~VrFlinger(); - - // These functions are all called on surface flinger's main thread. - void OnBootFinished(); - void GrantDisplayOwnership(); - void SeizeDisplayOwnership(); - - // dump all vr flinger state. - std::string Dump(); - - private: - VrFlinger(); - bool Init(Hwc2::Composer* hidl, - hwc2_display_t primary_display_id, - RequestDisplayCallback request_display_callback); - - // Needs to be a separate class for binder's ref counting - class PersistentVrStateCallback : public BnPersistentVrStateCallbacks { - public: - explicit PersistentVrStateCallback( - RequestDisplayCallback request_display_callback) - : request_display_callback_(request_display_callback) {} - void onPersistentVrStateChanged(bool enabled) override; - private: - RequestDisplayCallback request_display_callback_; - }; - - std::thread dispatcher_thread_; - std::unique_ptr dispatcher_; - std::shared_ptr display_service_; - sp persistent_vr_state_callback_; - RequestDisplayCallback request_display_callback_; -}; - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_VR_FLINGER_H_ diff --git a/libs/vr/libvrflinger/tests/Android.bp b/libs/vr/libvrflinger/tests/Android.bp deleted file mode 100644 index 095f556609..0000000000 --- a/libs/vr/libvrflinger/tests/Android.bp +++ /dev/null @@ -1,47 +0,0 @@ -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_native_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_native_license"], -} - -shared_libs = [ - "android.hardware.configstore-utils", - "android.hardware.configstore@1.0", - "libbinder", - "libbufferhubqueue", - "libcutils", - "libgui", - "libhidlbase", - "liblog", - "libui", - "libutils", - "libnativewindow", - "libpdx_default_transport", - "libSurfaceFlingerProp", -] - -static_libs = [ - "libdisplay", -] - -cc_test { - srcs: ["vrflinger_test.cpp"], - // See go/apct-presubmit for documentation on how this .filter file is used - // by Android's automated testing infrastructure for test filtering. - data: ["vrflinger_test.filter"], - static_libs: static_libs, - shared_libs: shared_libs, - cflags: [ - "-DLOG_TAG=\"VrFlingerTest\"", - "-DTRACE=0", - "-O0", - "-g", - "-Wall", - "-Werror", - ], - header_libs: ["libsurfaceflinger_headers"], - name: "vrflinger_test", -} diff --git a/libs/vr/libvrflinger/tests/vrflinger_test.cpp b/libs/vr/libvrflinger/tests/vrflinger_test.cpp deleted file mode 100644 index ac44f74151..0000000000 --- a/libs/vr/libvrflinger/tests/vrflinger_test.cpp +++ /dev/null @@ -1,226 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -using namespace android::hardware::configstore; -using namespace android::hardware::configstore::V1_0; -using android::dvr::display::DisplayClient; -using android::dvr::display::Surface; -using android::dvr::display::SurfaceAttribute; -using android::dvr::display::SurfaceAttributeValue; - -namespace android { -namespace dvr { - -// The transaction code for asking surface flinger if vr flinger is active. This -// is done as a hidden api since it's only used for tests. See the "case 1028" -// block in SurfaceFlinger::onTransact() in SurfaceFlinger.cpp. -constexpr uint32_t kIsVrFlingerActiveTransactionCode = 1028; - -// The maximum amount of time to give vr flinger to activate/deactivate. If the -// switch hasn't completed in this amount of time, the test will fail. -constexpr auto kVrFlingerSwitchMaxTime = std::chrono::seconds(1); - -// How long to wait between each check to see if the vr flinger switch -// completed. -constexpr auto kVrFlingerSwitchPollInterval = std::chrono::milliseconds(50); - -// A Binder connection to surface flinger. -class SurfaceFlingerConnection { - public: - static std::unique_ptr Create() { - sp surface_flinger = interface_cast( - defaultServiceManager()->getService(String16("SurfaceFlinger"))); - if (surface_flinger == nullptr) { - return nullptr; - } - - return std::unique_ptr( - new SurfaceFlingerConnection(surface_flinger)); - } - - // Returns true if the surface flinger process is still running. We use this - // to detect if surface flinger has crashed. - bool IsAlive() { - IInterface::asBinder(surface_flinger_)->pingBinder(); - return IInterface::asBinder(surface_flinger_)->isBinderAlive(); - } - - // Return true if vr flinger is currently active, false otherwise. If there's - // an error communicating with surface flinger, std::nullopt is returned. - std::optional IsVrFlingerActive() { - Parcel data, reply; - status_t result = - data.writeInterfaceToken(surface_flinger_->getInterfaceDescriptor()); - if (result != OK) { - return std::nullopt; - } - result = IInterface::asBinder(surface_flinger_) - ->transact(kIsVrFlingerActiveTransactionCode, data, &reply); - if (result != OK) { - return std::nullopt; - } - bool vr_flinger_active; - result = reply.readBool(&vr_flinger_active); - if (result != OK) { - return std::nullopt; - } - return vr_flinger_active; - } - - enum class VrFlingerSwitchResult : int8_t { - kSuccess, - kTimedOut, - kCommunicationError, - kSurfaceFlingerDied - }; - - // Wait for vr flinger to become active or inactive. - VrFlingerSwitchResult WaitForVrFlinger(bool wait_active) { - return WaitForVrFlingerTimed(wait_active, kVrFlingerSwitchPollInterval, - kVrFlingerSwitchMaxTime); - } - - // Wait for vr flinger to become active or inactive, specifying custom timeouts. - VrFlingerSwitchResult WaitForVrFlingerTimed(bool wait_active, - std::chrono::milliseconds pollInterval, std::chrono::seconds timeout) { - auto start_time = std::chrono::steady_clock::now(); - while (1) { - std::this_thread::sleep_for(pollInterval); - if (!IsAlive()) { - return VrFlingerSwitchResult::kSurfaceFlingerDied; - } - std::optional vr_flinger_active = IsVrFlingerActive(); - if (!vr_flinger_active.has_value()) { - return VrFlingerSwitchResult::kCommunicationError; - } - if (vr_flinger_active.value() == wait_active) { - return VrFlingerSwitchResult::kSuccess; - } else if (std::chrono::steady_clock::now() - start_time > timeout) { - return VrFlingerSwitchResult::kTimedOut; - } - } - } - - private: - SurfaceFlingerConnection(sp surface_flinger) - : surface_flinger_(surface_flinger) {} - - sp surface_flinger_ = nullptr; -}; - -// This test activates vr flinger by creating a vr flinger surface, then -// deactivates vr flinger by destroying the surface. We verify that vr flinger -// is activated and deactivated as expected, and that surface flinger doesn't -// crash. -// -// If the device doesn't support vr flinger (as repoted by ConfigStore), the -// test does nothing. -// -// If the device is a standalone vr device, the test also does nothing, since -// this test verifies the behavior of display handoff from surface flinger to vr -// flinger and back, and standalone devices never hand control of the display -// back to surface flinger. -TEST(VrFlingerTest, ActivateDeactivate) { - android::ProcessState::self()->startThreadPool(); - - // Exit immediately if the device doesn't support vr flinger. This ConfigStore - // check is the same mechanism used by surface flinger to decide if it should - // initialize vr flinger. - bool vr_flinger_enabled = android::sysprop::use_vr_flinger(false); - if (!vr_flinger_enabled) { - return; - } - - auto surface_flinger_connection = SurfaceFlingerConnection::Create(); - ASSERT_NE(surface_flinger_connection, nullptr); - - // Verify we start off with vr flinger disabled. - ASSERT_TRUE(surface_flinger_connection->IsAlive()); - auto vr_flinger_active = surface_flinger_connection->IsVrFlingerActive(); - ASSERT_TRUE(vr_flinger_active.has_value()); - ASSERT_FALSE(vr_flinger_active.value()); - - // Create a vr flinger surface, and verify vr flinger becomes active. - // Introduce a scope so that, at the end of the scope, the vr flinger surface - // is destroyed, and vr flinger deactivates. - { - auto display_client = DisplayClient::Create(); - ASSERT_NE(display_client, nullptr); - auto metrics = display_client->GetDisplayMetrics(); - ASSERT_TRUE(metrics.ok()); - - auto surface = Surface::CreateSurface({ - {SurfaceAttribute::Direct, SurfaceAttributeValue(true)}, - {SurfaceAttribute::Visible, SurfaceAttributeValue(true)}, - }); - ASSERT_TRUE(surface.ok()); - ASSERT_TRUE(surface.get() != nullptr); - - auto queue = surface.get()->CreateQueue( - metrics.get().display_width, metrics.get().display_height, - /*layer_count=*/1, AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM, - AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | - AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | - AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, - /*capacity=*/1, - /*metadata_size=*/0); - ASSERT_TRUE(queue.ok()); - ASSERT_TRUE(queue.get() != nullptr); - - size_t slot; - pdx::LocalHandle release_fence; - auto buffer = queue.get()->Dequeue(/*timeout=*/0, &slot, &release_fence); - ASSERT_TRUE(buffer.ok()); - ASSERT_TRUE(buffer.get() != nullptr); - - ASSERT_EQ(buffer.get()->width(), metrics.get().display_width); - ASSERT_EQ(buffer.get()->height(), metrics.get().display_height); - - void* raw_buf = nullptr; - ASSERT_GE(buffer.get()->buffer()->Lock( - AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, /*x=*/0, /*y=*/0, - buffer.get()->width(), buffer.get()->height(), &raw_buf), - 0); - ASSERT_NE(raw_buf, nullptr); - uint32_t* pixels = static_cast(raw_buf); - - for (int i = 0; i < buffer.get()->stride() * buffer.get()->height(); ++i) { - pixels[i] = 0x0000ff00; - } - - ASSERT_GE(buffer.get()->buffer()->Unlock(), 0); - - ASSERT_GE(buffer.get()->Post(/*ready_fence=*/pdx::LocalHandle()), 0); - - ASSERT_EQ( - surface_flinger_connection->WaitForVrFlinger(/*wait_active=*/true), - SurfaceFlingerConnection::VrFlingerSwitchResult::kSuccess); - } - - // Now that the vr flinger surface is destroyed, vr flinger should deactivate. - ASSERT_EQ( - surface_flinger_connection->WaitForVrFlinger(/*wait_active=*/false), - SurfaceFlingerConnection::VrFlingerSwitchResult::kSuccess); -} - -} // namespace dvr -} // namespace android diff --git a/libs/vr/libvrflinger/tests/vrflinger_test.filter b/libs/vr/libvrflinger/tests/vrflinger_test.filter deleted file mode 100644 index 030bb7b67c..0000000000 --- a/libs/vr/libvrflinger/tests/vrflinger_test.filter +++ /dev/null @@ -1,5 +0,0 @@ -{ - "presubmit": { - "filter": "BootVrFlingerTest.*" - } -} diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp deleted file mode 100644 index a8a847664f..0000000000 --- a/libs/vr/libvrflinger/vr_flinger.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "DisplayHardware/ComposerHal.h" -#include "display_manager_service.h" -#include "display_service.h" - -namespace android { -namespace dvr { - -std::unique_ptr VrFlinger::Create( - Hwc2::Composer* hidl, hwc2_display_t primary_display_id, - RequestDisplayCallback request_display_callback) { - std::unique_ptr vr_flinger(new VrFlinger); - if (vr_flinger->Init(hidl, primary_display_id, request_display_callback)) - return vr_flinger; - else - return nullptr; -} - -VrFlinger::VrFlinger() {} - -VrFlinger::~VrFlinger() { - if (persistent_vr_state_callback_.get()) { - sp vr_manager = interface_cast( - defaultServiceManager()->checkService(String16("vrmanager"))); - if (vr_manager.get()) { - vr_manager->unregisterPersistentVrStateListener( - persistent_vr_state_callback_); - } - } - - if (dispatcher_) - dispatcher_->SetCanceled(true); - if (dispatcher_thread_.joinable()) - dispatcher_thread_.join(); -} - -bool VrFlinger::Init(Hwc2::Composer* hidl, - hwc2_display_t primary_display_id, - RequestDisplayCallback request_display_callback) { - if (!hidl || !request_display_callback) - return false; - - std::shared_ptr service; - - ALOGI("Starting up VrFlinger..."); - - // We need to be able to create endpoints with full perms. - umask(0000); - - android::ProcessState::self()->startThreadPool(); - - request_display_callback_ = request_display_callback; - - dispatcher_ = android::pdx::ServiceDispatcher::Create(); - CHECK_ERROR(!dispatcher_, error, "Failed to create service dispatcher."); - - display_service_ = android::dvr::DisplayService::Create( - hidl, primary_display_id, request_display_callback); - CHECK_ERROR(!display_service_, error, "Failed to create display service."); - dispatcher_->AddService(display_service_); - - service = android::dvr::DisplayManagerService::Create(display_service_); - CHECK_ERROR(!service, error, "Failed to create display manager service."); - dispatcher_->AddService(service); - - dispatcher_thread_ = std::thread([this]() { - prctl(PR_SET_NAME, reinterpret_cast("VrDispatch"), 0, 0, 0); - ALOGI("Entering message loop."); - - setpriority(PRIO_PROCESS, 0, android::PRIORITY_URGENT_DISPLAY); - set_sched_policy(0, SP_FOREGROUND); - - int ret = dispatcher_->EnterDispatchLoop(); - if (ret < 0) { - ALOGE("Dispatch loop exited because: %s\n", strerror(-ret)); - } - }); - - return true; - -error: - return false; -} - -void VrFlinger::OnBootFinished() { - display_service_->OnBootFinished(); - sp vr_manager = interface_cast( - defaultServiceManager()->checkService(String16("vrmanager"))); - if (vr_manager.get()) { - persistent_vr_state_callback_ = - new PersistentVrStateCallback(request_display_callback_); - vr_manager->registerPersistentVrStateListener( - persistent_vr_state_callback_); - } else { - ALOGE("Unable to register vr flinger for persistent vr mode changes"); - } -} - -void VrFlinger::GrantDisplayOwnership() { - display_service_->GrantDisplayOwnership(); -} - -void VrFlinger::SeizeDisplayOwnership() { - display_service_->SeizeDisplayOwnership(); -} - -std::string VrFlinger::Dump() { - // TODO(karthikrs): Add more state information here. - return display_service_->DumpState(0/*unused*/); -} - -void VrFlinger::PersistentVrStateCallback::onPersistentVrStateChanged( - bool enabled) { - ALOGV("Notified persistent vr mode is %s", enabled ? "on" : "off"); - // TODO(eieio): Determine the correct signal to request display control. - // Persistent VR mode is not enough. - // request_display_callback_(enabled); -} -} // namespace dvr -} // namespace android -- cgit v1.2.3-59-g8ed1b From 6e592063c3977b11956f7a02957ad0049061c3e5 Mon Sep 17 00:00:00 2001 From: Chavi Weingarten Date: Tue, 19 Oct 2021 16:41:29 -0400 Subject: Use strong reference to parent Handle when creating layer If LayerCreatedState holds a weak reference to the parent handle the following can occur: 1. handleLayerCreatedLocked is called and promotes the handle to a strong ref. 2. The client reference to that layer is removed. 3. When handleLayerCreatedLocked returns, the last reference is dropped. The Handle dtor is called which then calls onHandleDestroyed. That function tries to acquire the lock, but it's already held by the caller. 4. This will cause a deadlock. Instead, hold a strong reference in the LayerCreatedState. The reference will be held until flushTransactionQueues finishes, which will then clear the Handle reference. This occurs outside the lock so there should be no issue Fixes: 202621651 Test: Hard to reproduce, but no other issues Change-Id: I0b1ea54b63cbdef1fcf96eedffa4fbfa6959f697 --- services/surfaceflinger/SurfaceFlinger.cpp | 6 +++--- services/surfaceflinger/SurfaceFlinger.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e84dce4a23..cfd051cd88 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -6758,7 +6758,7 @@ void TransactionState::traverseStatesWithBuffers( } void SurfaceFlinger::setLayerCreatedState(const sp& handle, const wp& layer, - const wp& parent, const wp parentLayer, + const sp& parent, const wp parentLayer, const wp& producer, bool addToRoot) { Mutex::Autolock lock(mCreatedLayersLock); mCreatedLayers[handle->localBinder()] = @@ -6802,9 +6802,9 @@ sp SurfaceFlinger::handleLayerCreatedLocked(const sp& handle) { sp parent; bool allowAddRoot = state->addToRoot; if (state->initialParent != nullptr) { - parent = fromHandle(state->initialParent.promote()).promote(); + parent = fromHandle(state->initialParent).promote(); if (parent == nullptr) { - ALOGE("Invalid parent %p", state->initialParent.unsafe_get()); + ALOGE("Invalid parent %p", state->initialParent.get()); allowAddRoot = false; } } else if (state->initialParentLayer != nullptr) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 7895825cb5..5fa509e24f 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1344,7 +1344,7 @@ private: GUARDED_BY(mStateLock); mutable Mutex mCreatedLayersLock; struct LayerCreatedState { - LayerCreatedState(const wp& layer, const wp& parent, + LayerCreatedState(const wp& layer, const sp& parent, const wp parentLayer, const wp& producer, bool addToRoot) : layer(layer), initialParent(parent), @@ -1354,7 +1354,7 @@ private: wp layer; // Indicates the initial parent of the created layer, only used for creating layer in // SurfaceFlinger. If nullptr, it may add the created layer into the current root layers. - wp initialParent; + sp initialParent; wp initialParentLayer; // Indicates the initial graphic buffer producer of the created layer, only used for // creating layer in SurfaceFlinger. @@ -1369,7 +1369,7 @@ private: // thread. std::unordered_map> mCreatedLayers; void setLayerCreatedState(const sp& handle, const wp& layer, - const wp& parent, const wp parentLayer, + const sp& parent, const wp parentLayer, const wp& producer, bool addToRoot); auto getLayerCreatedState(const sp& handle); sp handleLayerCreatedLocked(const sp& handle) REQUIRES(mStateLock); -- cgit v1.2.3-59-g8ed1b From 4928bfd9284c4fca80e1e4d0b0322cfddd7037f9 Mon Sep 17 00:00:00 2001 From: Lais Andrade Date: Wed, 25 Aug 2021 18:21:12 +0100 Subject: Small rename on vibrator HAL wrapper method Rename checkAndLogFailure to isFailedLogged, since the boolean returned is counter-intuitive to the previous method name. Bug: 195595741 Test: VibratorTest Change-Id: I3b8ec6545fa45eaf4e5942565ca84733ffa7934d --- services/vibratorservice/VibratorHalWrapper.cpp | 15 +++++++-- .../VibratorManagerHalController.cpp | 2 +- .../vibratorservice/VibratorHalController.h | 2 +- .../include/vibratorservice/VibratorHalWrapper.h | 38 +++++++++++----------- 4 files changed, 33 insertions(+), 24 deletions(-) diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp index a375808ce4..63ecaec06f 100644 --- a/services/vibratorservice/VibratorHalWrapper.cpp +++ b/services/vibratorservice/VibratorHalWrapper.cpp @@ -402,12 +402,21 @@ HalResult> AidlHalWrapper::getPrimitiveDurationsIntern auto primitiveIdx = static_cast(primitive); if (primitiveIdx >= durations.size()) { // Safety check, should not happen if enum_range is correct. + ALOGE("Supported primitive %zu is outside range [0,%zu), skipping load duration", + primitiveIdx, durations.size()); continue; } int32_t duration = 0; - auto status = getHal()->getPrimitiveDuration(primitive, &duration); - if (!status.isOk()) { - return HalResult>::failed(status.toString8().c_str()); + auto result = getHal()->getPrimitiveDuration(primitive, &duration); + auto halResult = HalResult::fromStatus(result, duration); + if (halResult.isUnsupported()) { + // Should not happen, supported primitives should always support requesting duration. + ALOGE("Supported primitive %zu returned unsupported for getPrimitiveDuration", + primitiveIdx); + } + if (halResult.isFailed()) { + // Fail entire request if one request has failed. + return HalResult>::failed(result.toString8().c_str()); } durations[primitiveIdx] = milliseconds(duration); } diff --git a/services/vibratorservice/VibratorManagerHalController.cpp b/services/vibratorservice/VibratorManagerHalController.cpp index 6bf658185c..0df0bfa19a 100644 --- a/services/vibratorservice/VibratorManagerHalController.cpp +++ b/services/vibratorservice/VibratorManagerHalController.cpp @@ -45,7 +45,7 @@ static constexpr int MAX_RETRIES = 1; template HalResult ManagerHalController::processHalResult(HalResult result, const char* functionName) { if (result.isFailed()) { - ALOGE("%s failed: %s", functionName, result.errorMessage()); + ALOGE("VibratorManager HAL %s failed: %s", functionName, result.errorMessage()); std::lock_guard lock(mConnectedHalMutex); mConnectedHal->tryReconnect(); } diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalController.h b/services/vibratorservice/include/vibratorservice/VibratorHalController.h index 6c31e2b882..6b73d17b0a 100644 --- a/services/vibratorservice/include/vibratorservice/VibratorHalController.h +++ b/services/vibratorservice/include/vibratorservice/VibratorHalController.h @@ -103,7 +103,7 @@ private: for (int i = 0; i < MAX_RETRIES; i++) { T result = halFn(hal.get()); - if (result.checkAndLogFailure(functionName)) { + if (result.isFailedLogged(functionName)) { tryReconnect(); } else { return result; diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h index 68d6647ede..d2cc9ad7df 100644 --- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h +++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h @@ -69,9 +69,9 @@ public: bool isFailed() const { return !mUnsupported && !mValue.has_value(); } bool isUnsupported() const { return mUnsupported; } const char* errorMessage() const { return mErrorMessage.c_str(); } - bool checkAndLogFailure(const char* functionName) const { + bool isFailedLogged(const char* functionNameForLogging) const { if (isFailed()) { - ALOGE("%s failed: %s", functionName, errorMessage()); + ALOGE("Vibrator HAL %s failed: %s", functionNameForLogging, errorMessage()); return true; } return false; @@ -107,9 +107,9 @@ public: bool isFailed() const { return !mUnsupported && mFailed; } bool isUnsupported() const { return mUnsupported; } const char* errorMessage() const { return mErrorMessage.c_str(); } - bool checkAndLogFailure(const char* functionName) const { + bool isFailedLogged(const char* functionNameForLogging) const { if (isFailed()) { - ALOGE("%s failed: %s", functionName, errorMessage()); + ALOGE("Vibrator HAL %s failed: %s", functionNameForLogging, errorMessage()); return true; } return false; @@ -192,21 +192,21 @@ public: const HalResult qFactor; const HalResult> maxAmplitudes; - bool checkAndLogFailure(const char*) const { - return capabilities.checkAndLogFailure("getCapabilities") || - supportedEffects.checkAndLogFailure("getSupportedEffects") || - supportedBraking.checkAndLogFailure("getSupportedBraking") || - supportedPrimitives.checkAndLogFailure("getSupportedPrimitives") || - primitiveDurations.checkAndLogFailure("getPrimitiveDuration") || - primitiveDelayMax.checkAndLogFailure("getPrimitiveDelayMax") || - pwlePrimitiveDurationMax.checkAndLogFailure("getPwlePrimitiveDurationMax") || - compositionSizeMax.checkAndLogFailure("getCompositionSizeMax") || - pwleSizeMax.checkAndLogFailure("getPwleSizeMax") || - minFrequency.checkAndLogFailure("getMinFrequency") || - resonantFrequency.checkAndLogFailure("getResonantFrequency") || - frequencyResolution.checkAndLogFailure("getFrequencyResolution") || - qFactor.checkAndLogFailure("getQFactor") || - maxAmplitudes.checkAndLogFailure("getMaxAmplitudes"); + bool isFailedLogged(const char*) const { + return capabilities.isFailedLogged("getCapabilities") || + supportedEffects.isFailedLogged("getSupportedEffects") || + supportedBraking.isFailedLogged("getSupportedBraking") || + supportedPrimitives.isFailedLogged("getSupportedPrimitives") || + primitiveDurations.isFailedLogged("getPrimitiveDuration") || + primitiveDelayMax.isFailedLogged("getPrimitiveDelayMax") || + pwlePrimitiveDurationMax.isFailedLogged("getPwlePrimitiveDurationMax") || + compositionSizeMax.isFailedLogged("getCompositionSizeMax") || + pwleSizeMax.isFailedLogged("getPwleSizeMax") || + minFrequency.isFailedLogged("getMinFrequency") || + resonantFrequency.isFailedLogged("getResonantFrequency") || + frequencyResolution.isFailedLogged("getFrequencyResolution") || + qFactor.isFailedLogged("getQFactor") || + maxAmplitudes.isFailedLogged("getMaxAmplitudes"); } }; -- cgit v1.2.3-59-g8ed1b From 23e07500a900bed481d87f0118392966244f36b8 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Fri, 15 Oct 2021 11:58:19 +0000 Subject: Compute unique layer name in with sequence Remove 'getUniqueLayerName' so we could remove stack lock from 'createLayer'. Bug: 202621651 Test: atest libsurfaceflinger_unittest Test: atest SurfaceFlinger_test Change-Id: If5f4386b6da99bd540231b0c197c59a5823d7d4a --- services/surfaceflinger/Layer.cpp | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 39 ++++------------------ services/surfaceflinger/SurfaceFlinger.h | 2 -- .../tests/SurfaceInterceptor_test.cpp | 22 ++++++------ 4 files changed, 20 insertions(+), 45 deletions(-) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 68ca2f08ad..3b98d500cf 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -88,7 +88,7 @@ std::atomic Layer::sSequence{1}; Layer::Layer(const LayerCreationArgs& args) : mFlinger(args.flinger), - mName(args.name), + mName(base::StringPrintf("%s#%d", args.name.c_str(), sequence)), mClientRef(args.client), mWindowType( static_cast(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0))) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5f4acc9cc5..e565bbb2b8 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4209,7 +4209,7 @@ status_t SurfaceFlinger::mirrorLayer(const sp& client, const sp sp mirrorLayer; sp mirrorFrom; - std::string uniqueName = getUniqueLayerName("MirrorRoot"); + std::string layerName = "MirrorRoot"; { Mutex::Autolock _l(mStateLock); @@ -4218,7 +4218,7 @@ status_t SurfaceFlinger::mirrorLayer(const sp& client, const sp return NAME_NOT_FOUND; } - status_t result = createContainerLayer(client, std::move(uniqueName), -1, -1, 0, + status_t result = createContainerLayer(client, std::move(layerName), -1, -1, 0, LayerMetadata(), outHandle, &mirrorLayer); if (result != NO_ERROR) { return result; @@ -4252,12 +4252,12 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie sp layer; - std::string uniqueName = getUniqueLayerName(name.string()); + std::string layerName{name.string()}; switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { case ISurfaceComposerClient::eFXSurfaceBufferQueue: case ISurfaceComposerClient::eFXSurfaceBufferState: { - result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags, + result = createBufferStateLayer(client, std::move(layerName), w, h, flags, std::move(metadata), handle, &layer); std::atomic* pendingBufferCounter = layer->getPendingBufferCounter(); if (pendingBufferCounter) { @@ -4274,7 +4274,7 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie return BAD_VALUE; } - result = createEffectLayer(client, std::move(uniqueName), w, h, flags, + result = createEffectLayer(client, std::move(layerName), w, h, flags, std::move(metadata), handle, &layer); break; case ISurfaceComposerClient::eFXSurfaceContainer: @@ -4284,7 +4284,7 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie int(w), int(h)); return BAD_VALUE; } - result = createContainerLayer(client, std::move(uniqueName), w, h, flags, + result = createContainerLayer(client, std::move(layerName), w, h, flags, std::move(metadata), handle, &layer); break; default: @@ -4302,38 +4302,12 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie if (result != NO_ERROR) { return result; } - mInterceptor->saveSurfaceCreation(layer); setTransactionFlags(eTransactionNeeded); *outLayerId = layer->sequence; return result; } -std::string SurfaceFlinger::getUniqueLayerName(const char* name) { - unsigned dupeCounter = 0; - - // Tack on our counter whether there is a hit or not, so everyone gets a tag - std::string uniqueName = base::StringPrintf("%s#%u", name, dupeCounter); - - // Grab the state lock since we're accessing mCurrentState - Mutex::Autolock lock(mStateLock); - - // Loop over layers until we're sure there is no matching name - bool matchFound = true; - while (matchFound) { - matchFound = false; - mCurrentState.traverse([&](Layer* layer) { - if (layer->getName() == uniqueName) { - matchFound = true; - uniqueName = base::StringPrintf("%s#%u", name, ++dupeCounter); - } - }); - } - - ALOGV_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name, uniqueName.c_str()); - return uniqueName; -} - status_t SurfaceFlinger::createBufferQueueLayer(const sp& client, std::string name, uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata, PixelFormat& format, @@ -6885,6 +6859,7 @@ sp SurfaceFlinger::handleLayerCreatedLocked(const sp& handle) { } } + mInterceptor->saveSurfaceCreation(layer); return layer; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index feee5dfcd7..276c7f6bfe 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -786,8 +786,6 @@ private: status_t mirrorLayer(const sp& client, const sp& mirrorFromHandle, sp* outHandle, int32_t* outLayerId); - std::string getUniqueLayerName(const char* name); - // called when all clients have released all their references to // this layer meaning it is entirely safe to destroy all // resources associated to this layer. diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index ee16f40b6d..2082c42001 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -19,6 +19,7 @@ #pragma clang diagnostic ignored "-Wconversion" #pragma clang diagnostic ignored "-Wextra" +#include #include #include #include @@ -56,10 +57,7 @@ std::vector BLUR_REGIONS_UPDATE; const String8 DISPLAY_NAME("SurfaceInterceptor Display Test"); constexpr auto TEST_BG_SURFACE_NAME = "BG Interceptor Test Surface"; constexpr auto TEST_FG_SURFACE_NAME = "FG Interceptor Test Surface"; -constexpr auto UNIQUE_TEST_BG_SURFACE_NAME = "BG Interceptor Test Surface#0"; -constexpr auto UNIQUE_TEST_FG_SURFACE_NAME = "FG Interceptor Test Surface#0"; constexpr auto LAYER_NAME = "Layer Create and Delete Test"; -constexpr auto UNIQUE_LAYER_NAME = "Layer Create and Delete Test#0"; constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.winscope"; @@ -105,11 +103,15 @@ static void disableInterceptor() { system("service call SurfaceFlinger 1020 i32 0 > /dev/null"); } +std::string getUniqueName(const std::string& name, const Increment& increment) { + return base::StringPrintf("%s#%d", name.c_str(), increment.surface_creation().id()); +} + int32_t getSurfaceId(const Trace& capturedTrace, const std::string& surfaceName) { int32_t layerId = 0; for (const auto& increment : capturedTrace.increment()) { if (increment.increment_case() == increment.kSurfaceCreation) { - if (increment.surface_creation().name() == surfaceName) { + if (increment.surface_creation().name() == getUniqueName(surfaceName, increment)) { layerId = increment.surface_creation().id(); } } @@ -293,8 +295,8 @@ void SurfaceInterceptorTest::setupBackgroundSurface() { } void SurfaceInterceptorTest::preProcessTrace(const Trace& trace) { - mBGLayerId = getSurfaceId(trace, UNIQUE_TEST_BG_SURFACE_NAME); - mFGLayerId = getSurfaceId(trace, UNIQUE_TEST_FG_SURFACE_NAME); + mBGLayerId = getSurfaceId(trace, TEST_BG_SURFACE_NAME); + mFGLayerId = getSurfaceId(trace, TEST_FG_SURFACE_NAME); } void SurfaceInterceptorTest::captureTest(TestTransactionAction action, @@ -752,9 +754,9 @@ void SurfaceInterceptorTest::assertAllUpdatesFound(const Trace& trace) { } bool SurfaceInterceptorTest::surfaceCreationFound(const Increment& increment, bool foundSurface) { - bool isMatch(increment.surface_creation().name() == UNIQUE_LAYER_NAME && - increment.surface_creation().w() == SIZE_UPDATE && - increment.surface_creation().h() == SIZE_UPDATE); + bool isMatch(increment.surface_creation().name() == getUniqueName(LAYER_NAME, increment) && + increment.surface_creation().w() == SIZE_UPDATE && + increment.surface_creation().h() == SIZE_UPDATE); if (isMatch && !foundSurface) { foundSurface = true; } else if (isMatch && foundSurface) { @@ -808,7 +810,7 @@ bool SurfaceInterceptorTest::singleIncrementFound(const Trace& trace, break; case Increment::IncrementCase::kSurfaceDeletion: // Find the id of created surface. - targetId = getSurfaceId(trace, UNIQUE_LAYER_NAME); + targetId = getSurfaceId(trace, LAYER_NAME); foundIncrement = surfaceDeletionFound(increment, targetId, foundIncrement); break; case Increment::IncrementCase::kDisplayCreation: -- cgit v1.2.3-59-g8ed1b From c6d2d2b11684f6d306ef0fd12c909b185158e889 Mon Sep 17 00:00:00 2001 From: Rob Carr Date: Mon, 25 Oct 2021 16:51:49 +0000 Subject: Revert "Layer: Use raw pointers for Current/Drawing parent" This reverts commit cbdb79a195e6c690e16948a7e7c3abbd36414b17. Bug: 203175614 Bug: 203559094 Change-Id: I5432ad46bfbbe5a009e3fb72ae7ac129263260ce --- services/surfaceflinger/BufferLayer.cpp | 2 +- services/surfaceflinger/BufferStateLayer.cpp | 2 +- services/surfaceflinger/Layer.cpp | 77 ++++++++++------------ services/surfaceflinger/Layer.h | 6 +- services/surfaceflinger/SurfaceFlinger.cpp | 7 +- .../tests/unittests/TestableSurfaceFlinger.h | 2 +- 6 files changed, 42 insertions(+), 54 deletions(-) diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 82c91e7d30..8de43e0fe6 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -223,7 +223,7 @@ std::optional BufferLayer::prepareCli * of a camera where the buffer remains in native orientation, * we want the pixels to always be upright. */ - auto p = mDrawingParent; + sp p = mDrawingParent.promote(); if (p != nullptr) { const auto parentTransform = p->getTransform(); tr = tr * inverseOrientation(parentTransform.getOrientation()); diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index ba193c3be2..4eeaba154f 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -989,7 +989,7 @@ void BufferStateLayer::tracePendingBufferCount(int32_t pendingBuffers) { * how to go from screen space back to window space. */ ui::Transform BufferStateLayer::getInputTransform() const { - auto parent = mDrawingParent; + sp parent = mDrawingParent.promote(); if (parent == nullptr) { return ui::Transform(); } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5707c67a56..4f4a897084 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -179,23 +179,9 @@ Layer::~Layer() { if (mDrawingState.sidebandStream != nullptr) { mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount(); } - if (mHadClonedChild) { mFlinger->mNumClones--; } - - for (auto const& child : mCurrentChildren) { - if (child->mCurrentParent == this) child->mCurrentParent = nullptr; - if (child->mDrawingParent == this) { - child->mDrawingParent = nullptr; - } - } - for (auto const& child : mDrawingChildren) { - if (child->mCurrentParent == this) child->mCurrentParent = nullptr; - if (child->mDrawingParent == this) { - child->mDrawingParent = nullptr; - } - } } LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp client, std::string name, @@ -251,7 +237,7 @@ void Layer::removeFromCurrentState() { } sp Layer::getRootLayer() { - auto parent = getParent(); + sp parent = getParent(); if (parent == nullptr) { return this; } @@ -676,7 +662,7 @@ bool Layer::isSecure() const { return true; } - const auto p = mDrawingParent; + const auto p = mDrawingParent.promote(); return (p != nullptr) ? p->isSecure() : false; } @@ -859,7 +845,7 @@ bool Layer::isTrustedOverlay() const { if (getDrawingState().isTrustedOverlay) { return true; } - const auto p = mDrawingParent; + const auto& p = mDrawingParent.promote(); return (p != nullptr) && p->isTrustedOverlay(); } @@ -1039,7 +1025,7 @@ int32_t Layer::getFrameRateSelectionPriority() const { return mDrawingState.frameRateSelectionPriority; } // If not, search whether its parents have it set. - auto parent = getParent(); + sp parent = getParent(); if (parent != nullptr) { return parent->getFrameRateSelectionPriority(); } @@ -1052,11 +1038,10 @@ bool Layer::isLayerFocusedBasedOnPriority(int32_t priority) { }; ui::LayerStack Layer::getLayerStack() const { - auto p = mDrawingParent; - if (p == nullptr) { - return getDrawingState().layerStack; + if (const auto parent = mDrawingParent.promote()) { + return parent->getLayerStack(); } - return mDrawingParent->getLayerStack(); + return getDrawingState().layerStack; } bool Layer::setShadowRadius(float shadowRadius) { @@ -1101,7 +1086,7 @@ StretchEffect Layer::getStretchEffect() const { return mDrawingState.stretchEffect; } - auto parent = mDrawingParent; + sp parent = getParent(); if (parent != nullptr) { auto effect = parent->getStretchEffect(); if (effect.hasEffect()) { @@ -1316,7 +1301,7 @@ Layer::FrameRate Layer::getFrameRateForLayerTree() const { bool Layer::isHiddenByPolicy() const { const State& s(mDrawingState); - auto parent = mDrawingParent; + const auto& parent = mDrawingParent.promote(); if (parent != nullptr && parent->isHiddenByPolicy()) { return true; } @@ -1363,7 +1348,7 @@ LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const { LayerDebugInfo info; const State& ds = getDrawingState(); info.mName = getName(); - auto parent = mDrawingParent; + sp parent = mDrawingParent.promote(); info.mParentName = parent ? parent->getName() : "none"s; info.mType = getType(); info.mTransparentRegion = ds.activeTransparentRegion_legacy; @@ -1595,7 +1580,7 @@ ssize_t Layer::removeChild(const sp& layer) { void Layer::setChildrenDrawingParent(const sp& newParent) { for (const sp& child : mDrawingChildren) { - child->mDrawingParent = newParent.get(); + child->mDrawingParent = newParent; child->computeBounds(newParent->mBounds, newParent->mEffectiveTransform, newParent->mEffectiveShadowRadius); } @@ -1615,7 +1600,7 @@ bool Layer::reparent(const sp& newParentHandle) { } } - auto parent = getParent(); + sp parent = getParent(); if (parent != nullptr) { parent->removeChild(this); } @@ -1650,7 +1635,7 @@ bool Layer::setColorTransform(const mat4& matrix) { mat4 Layer::getColorTransform() const { mat4 colorTransform = mat4(getDrawingState().colorTransform); - if (auto parent = mDrawingParent; parent != nullptr) { + if (sp parent = mDrawingParent.promote(); parent != nullptr) { colorTransform = parent->getColorTransform() * colorTransform; } return colorTransform; @@ -1658,7 +1643,7 @@ mat4 Layer::getColorTransform() const { bool Layer::hasColorTransform() const { bool hasColorTransform = getDrawingState().hasColorTransform; - if (auto parent = mDrawingParent; parent != nullptr) { + if (sp parent = mDrawingParent.promote(); parent != nullptr) { hasColorTransform = hasColorTransform || parent->hasColorTransform(); } return hasColorTransform; @@ -1672,7 +1657,7 @@ bool Layer::isLegacyDataSpace() const { } void Layer::setParent(const sp& layer) { - mCurrentParent = layer.get(); + mCurrentParent = layer; } int32_t Layer::getZ(LayerVector::StateSet) const { @@ -1876,7 +1861,7 @@ ui::Transform Layer::getTransform() const { } half Layer::getAlpha() const { - auto p = mDrawingParent; + const auto& p = mDrawingParent.promote(); half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf; return parentAlpha * getDrawingState().color.a; @@ -1887,7 +1872,7 @@ ui::Transform::RotationFlags Layer::getFixedTransformHint() const { if (fixedTransformHint != ui::Transform::ROT_INVALID) { return fixedTransformHint; } - auto p = mCurrentParent; + const auto& p = mCurrentParent.promote(); if (!p) return fixedTransformHint; return p->getFixedTransformHint(); } @@ -1898,7 +1883,7 @@ half4 Layer::getColor() const { } int32_t Layer::getBackgroundBlurRadius() const { - auto p = mDrawingParent; + const auto& p = mDrawingParent.promote(); half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf; return parentAlpha * getDrawingState().backgroundBlurRadius; @@ -1916,8 +1901,9 @@ const std::vector Layer::getBlurRegions() const { Layer::RoundedCornerState Layer::getRoundedCornerState() const { // Get parent settings RoundedCornerState parentSettings; - if (mDrawingParent != nullptr) { - parentSettings = mDrawingParent->getRoundedCornerState(); + const auto& parent = mDrawingParent.promote(); + if (parent != nullptr) { + parentSettings = parent->getRoundedCornerState(); if (parentSettings.radius > 0) { ui::Transform t = getActiveTransform(getDrawingState()); t = t.inverse(); @@ -2133,7 +2119,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet LayerProtoHelper::writeToProtoDeprecated(requestedTransform, layerInfo->mutable_requested_transform()); - auto parent = useDrawing ? mDrawingParent : mCurrentParent; + auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote(); if (parent != nullptr) { layerInfo->set_parent(parent->sequence); } else { @@ -2280,9 +2266,9 @@ void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& displayTra } void Layer::fillTouchOcclusionMode(WindowInfo& info) { - Layer* p = this; + sp p = this; while (p != nullptr && !p->hasInputInfo()) { - p = p->mDrawingParent; + p = p->mDrawingParent.promote(); } if (p != nullptr) { info.touchOcclusionMode = p->mDrawingState.inputInfo.touchOcclusionMode; @@ -2294,8 +2280,9 @@ gui::DropInputMode Layer::getDropInputMode() const { if (mode == gui::DropInputMode::ALL) { return mode; } - if (mDrawingParent) { - gui::DropInputMode parentMode = mDrawingParent->getDropInputMode(); + sp parent = mDrawingParent.promote(); + if (parent) { + gui::DropInputMode parentMode = parent->getDropInputMode(); if (parentMode != gui::DropInputMode::NONE) { return parentMode; } @@ -2322,7 +2309,8 @@ void Layer::handleDropInputMode(gui::WindowInfo& info) const { } // Check if the parent has set an alpha on the layer - if (mDrawingParent && mDrawingParent->getAlpha() != 1.0_hf) { + sp parent = mDrawingParent.promote(); + if (parent && parent->getAlpha() != 1.0_hf) { info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; ALOGV("Dropping input for %s as requested by policy because alpha=%f", getDebugName(), static_cast(getAlpha())); @@ -2420,10 +2408,10 @@ sp Layer::getClonedRoot() { if (mClonedChild != nullptr) { return this; } - if (mDrawingParent == nullptr) { + if (mDrawingParent == nullptr || mDrawingParent.promote() == nullptr) { return nullptr; } - return mDrawingParent->getClonedRoot(); + return mDrawingParent.promote()->getClonedRoot(); } bool Layer::hasInputInfo() const { @@ -2610,7 +2598,8 @@ bool Layer::isInternalDisplayOverlay() const { return true; } - return mDrawingParent && mDrawingParent->isInternalDisplayOverlay(); + sp parent = mDrawingParent.promote(); + return parent && parent->isInternalDisplayOverlay(); } void Layer::setClonedChild(const sp& clonedChild) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 07b2eb5130..8209c51ecb 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -795,12 +795,12 @@ public: // Returns index if removed, or negative value otherwise // for symmetry with Vector::remove ssize_t removeChild(const sp& layer); + sp getParent() const { return mCurrentParent.promote(); } // Should be called with the surfaceflinger statelock held bool isAtRoot() const { return mIsAtRoot; } void setIsAtRoot(bool isAtRoot) { mIsAtRoot = isAtRoot; } - Layer* getParent() const { return mCurrentParent; } bool hasParent() const { return getParent() != nullptr; } Rect getScreenBounds(bool reduceTransparentRegion = true) const; bool setChildLayer(const sp& childLayer, int32_t z); @@ -1007,8 +1007,8 @@ protected: LayerVector mCurrentChildren{LayerVector::StateSet::Current}; LayerVector mDrawingChildren{LayerVector::StateSet::Drawing}; - Layer* mCurrentParent = nullptr; - Layer* mDrawingParent = nullptr; + wp mCurrentParent; + wp mDrawingParent; // Window types from WindowManager.LayoutParams const gui::WindowInfo::Type mWindowType; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index acb81dc41c..81f20edca1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3412,7 +3412,6 @@ status_t SurfaceFlinger::addClientLayer(const sp& client, const spupdateTransformHint(mActiveDisplayTransformHint); - if (outTransformHint) { *outTransformHint = mActiveDisplayTransformHint; } @@ -3957,7 +3956,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( } if (what & layer_state_t::eLayerChanged) { // NOTE: index needs to be calculated before we update the state - auto p = layer->getParent(); + const auto& p = layer->getParent(); if (p == nullptr) { ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); if (layer->setLayer(s.z) && idx >= 0) { @@ -3975,7 +3974,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( } if (what & layer_state_t::eRelativeLayerChanged) { // NOTE: index needs to be calculated before we update the state - auto p = layer->getParent(); + const auto& p = layer->getParent(); const auto& relativeHandle = s.relativeLayerSurfaceControl ? s.relativeLayerSurfaceControl->getHandle() : nullptr; if (p == nullptr) { @@ -6126,7 +6125,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, return; } - auto p = layer; + sp p = layer; while (p != nullptr) { if (excludeLayers.count(p) != 0) { return; diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index db3b5722ec..7072439cea 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -289,7 +289,7 @@ public: } static void setLayerDrawingParent(const sp& layer, const sp& drawingParent) { - layer->mDrawingParent = drawingParent.get(); + layer->mDrawingParent = drawingParent; } /* ------------------------------------------------------------------------ -- cgit v1.2.3-59-g8ed1b From d2b0267be035d42df75f0bf2e9bd653d8b5619ff Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Tue, 19 Oct 2021 11:24:45 -0700 Subject: MotionEvent: Avoid clipping tranformed orientation angle values A recent refactor (ag/14556109) exposed an issue in the existing orientation angle transformation logic where the output was clipped incorrectly. There is no need to clip the ouput of atan2f because its output is in the range [-pi, pi], which conforms to the MotionEvent's orientation API. Test: manual with stylus and test app Bug: 202534592 Change-Id: I55df7470049922d0f579c2c1921dcacd0757ece1 --- libs/input/Input.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 390ff965ec..b4d9ab623c 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -56,13 +56,8 @@ float transformAngle(const ui::Transform& transform, float angleRadians) { transformedPoint.y -= origin.y; // Derive the transformed vector's clockwise angle from vertical. - float result = atan2f(transformedPoint.x, -transformedPoint.y); - if (result < -M_PI_2) { - result += M_PI; - } else if (result > M_PI_2) { - result -= M_PI; - } - return result; + // The return value of atan2f is in range [-pi, pi] which conforms to the orientation API. + return atan2f(transformedPoint.x, -transformedPoint.y); } vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) { -- cgit v1.2.3-59-g8ed1b From b47287e492c4e8ad6a487451971a848fc699807a Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Tue, 26 Oct 2021 16:30:11 +0000 Subject: Fix typo Change-Id: I1f942e612e8bacff536b47ef6b6e114c4d75fba6 --- libs/gui/include/gui/Surface.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index e5403512a9..40d096e1e5 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -429,11 +429,11 @@ protected: uint32_t mReqHeight; // mReqFormat is the buffer pixel format that will be requested at the next - // deuque operation. It is initialized to PIXEL_FORMAT_RGBA_8888. + // dequeue operation. It is initialized to PIXEL_FORMAT_RGBA_8888. PixelFormat mReqFormat; // mReqUsage is the set of buffer usage flags that will be requested - // at the next deuque operation. It is initialized to 0. + // at the next dequeue operation. It is initialized to 0. uint64_t mReqUsage; // mTimestamp is the timestamp that will be used for the next buffer queue -- cgit v1.2.3-59-g8ed1b From 026680a77dbd34fd6a9db7d83d3381ab2aae30cc Mon Sep 17 00:00:00 2001 From: Robin Lee Date: Mon, 26 Jul 2021 12:49:53 +0200 Subject: Split BlurFilter into interface + implementation With the first implementation being KawaseBlurFilter, which was previously in BlurFilter.cpp. Bug: 185365391 Test: atest BlurTests Change-Id: I265ec54a1a2e047b22d191c37bcb788f92ad0672 --- libs/renderengine/Android.bp | 2 +- libs/renderengine/skia/SkiaGLRenderEngine.cpp | 3 +- libs/renderengine/skia/filters/BlurFilter.cpp | 189 -------------------- libs/renderengine/skia/filters/BlurFilter.h | 26 +-- .../renderengine/skia/filters/KawaseBlurFilter.cpp | 190 +++++++++++++++++++++ libs/renderengine/skia/filters/KawaseBlurFilter.h | 69 ++++++++ 6 files changed, 270 insertions(+), 209 deletions(-) delete mode 100644 libs/renderengine/skia/filters/BlurFilter.cpp create mode 100644 libs/renderengine/skia/filters/KawaseBlurFilter.cpp create mode 100644 libs/renderengine/skia/filters/KawaseBlurFilter.h diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index 570c7bc08d..336ff684c1 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -93,7 +93,7 @@ filegroup { "skia/debug/CommonPool.cpp", "skia/debug/SkiaCapture.cpp", "skia/debug/SkiaMemoryReporter.cpp", - "skia/filters/BlurFilter.cpp", + "skia/filters/KawaseBlurFilter.cpp", "skia/filters/LinearEffect.cpp", "skia/filters/StretchShaderFactory.cpp" ], diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index d5ec774e9c..e6fb94d1c1 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -53,6 +53,7 @@ #include "SkBlendMode.h" #include "SkImageInfo.h" #include "filters/BlurFilter.h" +#include "filters/KawaseBlurFilter.h" #include "filters/LinearEffect.h" #include "log/log_main.h" #include "skia/debug/SkiaCapture.h" @@ -328,7 +329,7 @@ SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGL if (args.supportsBackgroundBlur) { ALOGD("Background Blurs Enabled"); - mBlurFilter = new BlurFilter(); + mBlurFilter = new KawaseBlurFilter(); } mCapture = std::make_unique(); } diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp deleted file mode 100644 index 2b6833e6e9..0000000000 --- a/libs/renderengine/skia/filters/BlurFilter.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "BlurFilter.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace android { -namespace renderengine { -namespace skia { - -BlurFilter::BlurFilter() { - SkString blurString(R"( - uniform shader child; - uniform float2 in_blurOffset; - uniform float2 in_maxSizeXY; - - half4 main(float2 xy) { - half4 c = child.eval(xy); - c += child.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), - clamp( in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); - c += child.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), - clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); - c += child.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), - clamp( in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); - c += child.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), - clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); - - return half4(c.rgb * 0.2, 1.0); - } - )"); - - auto [blurEffect, error] = SkRuntimeEffect::MakeForShader(blurString); - if (!blurEffect) { - LOG_ALWAYS_FATAL("RuntimeShader error: %s", error.c_str()); - } - mBlurEffect = std::move(blurEffect); - - SkString mixString(R"( - uniform shader blurredInput; - uniform shader originalInput; - uniform float mixFactor; - - half4 main(float2 xy) { - return half4(mix(originalInput.eval(xy), blurredInput.eval(xy), mixFactor)); - } - )"); - - auto [mixEffect, mixError] = SkRuntimeEffect::MakeForShader(mixString); - if (!mixEffect) { - LOG_ALWAYS_FATAL("RuntimeShader error: %s", mixError.c_str()); - } - mMixEffect = std::move(mixEffect); -} - -sk_sp BlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius, - const sk_sp input, const SkRect& blurRect) const { - // Kawase is an approximation of Gaussian, but it behaves differently from it. - // A radius transformation is required for approximating them, and also to introduce - // non-integer steps, necessary to smoothly interpolate large radii. - float tmpRadius = (float)blurRadius / 2.0f; - float numberOfPasses = std::min(kMaxPasses, (uint32_t)ceil(tmpRadius)); - float radiusByPasses = tmpRadius / (float)numberOfPasses; - - // create blur surface with the bit depth and colorspace of the original surface - SkImageInfo scaledInfo = input->imageInfo().makeWH(std::ceil(blurRect.width() * kInputScale), - std::ceil(blurRect.height() * kInputScale)); - - const float stepX = radiusByPasses; - const float stepY = radiusByPasses; - - // For sampling Skia's API expects the inverse of what logically seems appropriate. In this - // case you might expect Translate(blurRect.fLeft, blurRect.fTop) X Scale(kInverseInputScale) - // but instead we must do the inverse. - SkMatrix blurMatrix = SkMatrix::Translate(-blurRect.fLeft, -blurRect.fTop); - blurMatrix.postScale(kInputScale, kInputScale); - - // start by downscaling and doing the first blur pass - SkSamplingOptions linear(SkFilterMode::kLinear, SkMipmapMode::kNone); - SkRuntimeShaderBuilder blurBuilder(mBlurEffect); - blurBuilder.child("child") = - input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, blurMatrix); - blurBuilder.uniform("in_blurOffset") = SkV2{stepX * kInputScale, stepY * kInputScale}; - blurBuilder.uniform("in_maxSizeXY") = - SkV2{blurRect.width() * kInputScale, blurRect.height() * kInputScale}; - - sk_sp tmpBlur(blurBuilder.makeImage(context, nullptr, scaledInfo, false)); - - // And now we'll build our chain of scaled blur stages - for (auto i = 1; i < numberOfPasses; i++) { - const float stepScale = (float)i * kInputScale; - blurBuilder.child("child") = - tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear); - blurBuilder.uniform("in_blurOffset") = SkV2{stepX * stepScale, stepY * stepScale}; - blurBuilder.uniform("in_maxSizeXY") = - SkV2{blurRect.width() * kInputScale, blurRect.height() * kInputScale}; - tmpBlur = blurBuilder.makeImage(context, nullptr, scaledInfo, false); - } - - return tmpBlur; -} - -static SkMatrix getShaderTransform(const SkCanvas* canvas, const SkRect& blurRect, float scale) { - // 1. Apply the blur shader matrix, which scales up the blured surface to its real size - auto matrix = SkMatrix::Scale(scale, scale); - // 2. Since the blurred surface has the size of the layer, we align it with the - // top left corner of the layer position. - matrix.postConcat(SkMatrix::Translate(blurRect.fLeft, blurRect.fTop)); - // 3. Finally, apply the inverse canvas matrix. The snapshot made in the BlurFilter is in the - // original surface orientation. The inverse matrix has to be applied to align the blur - // surface with the current orientation/position of the canvas. - SkMatrix drawInverse; - if (canvas != nullptr && canvas->getTotalMatrix().invert(&drawInverse)) { - matrix.postConcat(drawInverse); - } - return matrix; -} - -void BlurFilter::drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, - const uint32_t blurRadius, const float blurAlpha, - const SkRect& blurRect, sk_sp blurredImage, - sk_sp input) { - ATRACE_CALL(); - - SkPaint paint; - paint.setAlphaf(blurAlpha); - - const auto blurMatrix = getShaderTransform(canvas, blurRect, kInverseInputScale); - SkSamplingOptions linearSampling(SkFilterMode::kLinear, SkMipmapMode::kNone); - const auto blurShader = blurredImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, - linearSampling, &blurMatrix); - - if (blurRadius < kMaxCrossFadeRadius) { - // For sampling Skia's API expects the inverse of what logically seems appropriate. In this - // case you might expect the matrix to simply be the canvas matrix. - SkMatrix inputMatrix; - if (!canvas->getTotalMatrix().invert(&inputMatrix)) { - ALOGE("matrix was unable to be inverted"); - } - - SkRuntimeShaderBuilder blurBuilder(mMixEffect); - blurBuilder.child("blurredInput") = blurShader; - blurBuilder.child("originalInput") = - input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linearSampling, - inputMatrix); - blurBuilder.uniform("mixFactor") = blurRadius / kMaxCrossFadeRadius; - - paint.setShader(blurBuilder.makeShader(nullptr, true)); - } else { - paint.setShader(blurShader); - } - - if (effectRegion.isRect()) { - if (blurAlpha == 1.0f) { - paint.setBlendMode(SkBlendMode::kSrc); - } - canvas->drawRect(effectRegion.rect(), paint); - } else { - paint.setAntiAlias(true); - canvas->drawRRect(effectRegion, paint); - } -} - -} // namespace skia -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/skia/filters/BlurFilter.h b/libs/renderengine/skia/filters/BlurFilter.h index 7110018367..1beadee092 100644 --- a/libs/renderengine/skia/filters/BlurFilter.h +++ b/libs/renderengine/skia/filters/BlurFilter.h @@ -27,29 +27,22 @@ namespace android { namespace renderengine { namespace skia { -/** - * This is an implementation of a Kawase blur, as described in here: - * https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/ - * 00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_notes.pdf - */ class BlurFilter { public: // Downsample FBO to improve performance static constexpr float kInputScale = 0.25f; // Downsample scale factor used to improve performance static constexpr float kInverseInputScale = 1.0f / kInputScale; - // Maximum number of render passes - static constexpr uint32_t kMaxPasses = 4; // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited // image, up to this radius. static constexpr float kMaxCrossFadeRadius = 10.0f; - explicit BlurFilter(); - virtual ~BlurFilter(){}; + explicit BlurFilter(){} + virtual ~BlurFilter(){} // Execute blur, saving it to a texture - sk_sp generate(GrRecordingContext* context, const uint32_t radius, - const sk_sp blurInput, const SkRect& blurRect) const; + virtual sk_sp generate(GrRecordingContext* context, const uint32_t radius, + const sk_sp blurInput, const SkRect& blurRect) const = 0; /** * Draw the blurred content (from the generate method) into the canvas. @@ -61,13 +54,10 @@ public: * @param blurredImage down-sampled blurred content that was produced by the generate() method * @param input original unblurred input that is used to crossfade with the blurredImage */ - void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, const uint32_t blurRadius, - const float blurAlpha, const SkRect& blurRect, sk_sp blurredImage, - sk_sp input); - -private: - sk_sp mBlurEffect; - sk_sp mMixEffect; + virtual void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, + const uint32_t blurRadius, const float blurAlpha, + const SkRect& blurRect, sk_sp blurredImage, + sk_sp input) = 0; }; } // namespace skia diff --git a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp new file mode 100644 index 0000000000..366d830b24 --- /dev/null +++ b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp @@ -0,0 +1,190 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include "KawaseBlurFilter.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { +namespace renderengine { +namespace skia { + +KawaseBlurFilter::KawaseBlurFilter(): BlurFilter() { + SkString blurString(R"( + uniform shader child; + uniform float2 in_blurOffset; + uniform float2 in_maxSizeXY; + + half4 main(float2 xy) { + half4 c = child.eval(xy); + c += child.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), + clamp( in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); + c += child.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), + clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); + c += child.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), + clamp( in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); + c += child.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), + clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); + + return half4(c.rgb * 0.2, 1.0); + } + )"); + + auto [blurEffect, error] = SkRuntimeEffect::MakeForShader(blurString); + if (!blurEffect) { + LOG_ALWAYS_FATAL("RuntimeShader error: %s", error.c_str()); + } + mBlurEffect = std::move(blurEffect); + + SkString mixString(R"( + uniform shader blurredInput; + uniform shader originalInput; + uniform float mixFactor; + + half4 main(float2 xy) { + return half4(mix(originalInput.eval(xy), blurredInput.eval(xy), mixFactor)); + } + )"); + + auto [mixEffect, mixError] = SkRuntimeEffect::MakeForShader(mixString); + if (!mixEffect) { + LOG_ALWAYS_FATAL("RuntimeShader error: %s", mixError.c_str()); + } + mMixEffect = std::move(mixEffect); +} + +sk_sp KawaseBlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius, + const sk_sp input, const SkRect& blurRect) + const { + // Kawase is an approximation of Gaussian, but it behaves differently from it. + // A radius transformation is required for approximating them, and also to introduce + // non-integer steps, necessary to smoothly interpolate large radii. + float tmpRadius = (float)blurRadius / 2.0f; + float numberOfPasses = std::min(kMaxPasses, (uint32_t)ceil(tmpRadius)); + float radiusByPasses = tmpRadius / (float)numberOfPasses; + + // create blur surface with the bit depth and colorspace of the original surface + SkImageInfo scaledInfo = input->imageInfo().makeWH(std::ceil(blurRect.width() * kInputScale), + std::ceil(blurRect.height() * kInputScale)); + + const float stepX = radiusByPasses; + const float stepY = radiusByPasses; + + // For sampling Skia's API expects the inverse of what logically seems appropriate. In this + // case you might expect Translate(blurRect.fLeft, blurRect.fTop) X Scale(kInverseInputScale) + // but instead we must do the inverse. + SkMatrix blurMatrix = SkMatrix::Translate(-blurRect.fLeft, -blurRect.fTop); + blurMatrix.postScale(kInputScale, kInputScale); + + // start by downscaling and doing the first blur pass + SkSamplingOptions linear(SkFilterMode::kLinear, SkMipmapMode::kNone); + SkRuntimeShaderBuilder blurBuilder(mBlurEffect); + blurBuilder.child("child") = + input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, blurMatrix); + blurBuilder.uniform("in_blurOffset") = SkV2{stepX * kInputScale, stepY * kInputScale}; + blurBuilder.uniform("in_maxSizeXY") = + SkV2{blurRect.width() * kInputScale, blurRect.height() * kInputScale}; + + sk_sp tmpBlur(blurBuilder.makeImage(context, nullptr, scaledInfo, false)); + + // And now we'll build our chain of scaled blur stages + for (auto i = 1; i < numberOfPasses; i++) { + const float stepScale = (float)i * kInputScale; + blurBuilder.child("child") = + tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear); + blurBuilder.uniform("in_blurOffset") = SkV2{stepX * stepScale, stepY * stepScale}; + blurBuilder.uniform("in_maxSizeXY") = + SkV2{blurRect.width() * kInputScale, blurRect.height() * kInputScale}; + tmpBlur = blurBuilder.makeImage(context, nullptr, scaledInfo, false); + } + + return tmpBlur; +} + +static SkMatrix getShaderTransform(const SkCanvas* canvas, const SkRect& blurRect, float scale) { + // 1. Apply the blur shader matrix, which scales up the blured surface to its real size + auto matrix = SkMatrix::Scale(scale, scale); + // 2. Since the blurred surface has the size of the layer, we align it with the + // top left corner of the layer position. + matrix.postConcat(SkMatrix::Translate(blurRect.fLeft, blurRect.fTop)); + // 3. Finally, apply the inverse canvas matrix. The snapshot made in the BlurFilter is in the + // original surface orientation. The inverse matrix has to be applied to align the blur + // surface with the current orientation/position of the canvas. + SkMatrix drawInverse; + if (canvas != nullptr && canvas->getTotalMatrix().invert(&drawInverse)) { + matrix.postConcat(drawInverse); + } + return matrix; +} + +void KawaseBlurFilter::drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, + const uint32_t blurRadius, const float blurAlpha, + const SkRect& blurRect, sk_sp blurredImage, + sk_sp input) { + ATRACE_CALL(); + + SkPaint paint; + paint.setAlphaf(blurAlpha); + + const auto blurMatrix = getShaderTransform(canvas, blurRect, kInverseInputScale); + SkSamplingOptions linearSampling(SkFilterMode::kLinear, SkMipmapMode::kNone); + const auto blurShader = blurredImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, + linearSampling, &blurMatrix); + + if (blurRadius < kMaxCrossFadeRadius) { + // For sampling Skia's API expects the inverse of what logically seems appropriate. In this + // case you might expect the matrix to simply be the canvas matrix. + SkMatrix inputMatrix; + if (!canvas->getTotalMatrix().invert(&inputMatrix)) { + ALOGE("matrix was unable to be inverted"); + } + + SkRuntimeShaderBuilder blurBuilder(mMixEffect); + blurBuilder.child("blurredInput") = blurShader; + blurBuilder.child("originalInput") = + input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linearSampling, + inputMatrix); + blurBuilder.uniform("mixFactor") = blurRadius / kMaxCrossFadeRadius; + + paint.setShader(blurBuilder.makeShader(nullptr, true)); + } else { + paint.setShader(blurShader); + } + + if (effectRegion.isRect()) { + if (blurAlpha == 1.0f) { + paint.setBlendMode(SkBlendMode::kSrc); + } + canvas->drawRect(effectRegion.rect(), paint); + } else { + paint.setAntiAlias(true); + canvas->drawRRect(effectRegion, paint); + } +} + +} // namespace skia +} // namespace renderengine +} // namespace android diff --git a/libs/renderengine/skia/filters/KawaseBlurFilter.h b/libs/renderengine/skia/filters/KawaseBlurFilter.h new file mode 100644 index 0000000000..d2731e3585 --- /dev/null +++ b/libs/renderengine/skia/filters/KawaseBlurFilter.h @@ -0,0 +1,69 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "BlurFilter.h" +#include +#include +#include +#include + +using namespace std; + +namespace android { +namespace renderengine { +namespace skia { + +/** + * This is an implementation of a Kawase blur, as described in here: + * https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/ + * 00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_notes.pdf + */ +class KawaseBlurFilter: public BlurFilter { +public: + // Maximum number of render passes + static constexpr uint32_t kMaxPasses = 4; + + explicit KawaseBlurFilter(); + virtual ~KawaseBlurFilter(){} + + // Execute blur, saving it to a texture + sk_sp generate(GrRecordingContext* context, const uint32_t radius, + const sk_sp blurInput, const SkRect& blurRect) const override; + + /** + * Draw the blurred content (from the generate method) into the canvas. + * @param canvas is the destination/output for the blur + * @param effectRegion the RoundRect in canvas coordinates that determines the blur coverage + * @param blurRadius radius of the blur used to determine the intensity of the crossfade effect + * @param blurAlpha alpha value applied to the effectRegion when the blur is drawn + * @param blurRect bounds of the blurredImage translated into canvas coordinates + * @param blurredImage down-sampled blurred content that was produced by the generate() method + * @param input original unblurred input that is used to crossfade with the blurredImage + */ + void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, const uint32_t blurRadius, + const float blurAlpha, const SkRect& blurRect, sk_sp blurredImage, + sk_sp input) override; + +private: + sk_sp mBlurEffect; + sk_sp mMixEffect; +}; + +} // namespace skia +} // namespace renderengine +} // namespace android -- cgit v1.2.3-59-g8ed1b From 2e98ade425332bca2dfe8a072393330232fb1e99 Mon Sep 17 00:00:00 2001 From: Robin Lee Date: Tue, 26 Oct 2021 18:20:53 +0200 Subject: Clean up KawaseBlurFilter The clamp() calls aren't necessary with the current design and since x/y are treated the same any duplicated code around stepX/stepY can also be deleted. This makes the shader a little simpler and reduces the number of intermediate const variables that are passed in twice for x and y. The reason for doing this is to prepare to use this code as a base for other implementations of blur. Bug: 185365391 Test: atest BlurTests Change-Id: I6c75d89dd10d568651f6a6183d25b170ab8526ad --- .../renderengine/skia/filters/KawaseBlurFilter.cpp | 28 ++++++---------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp index 366d830b24..e3a0e58649 100644 --- a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp +++ b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp @@ -35,20 +35,14 @@ namespace skia { KawaseBlurFilter::KawaseBlurFilter(): BlurFilter() { SkString blurString(R"( uniform shader child; - uniform float2 in_blurOffset; - uniform float2 in_maxSizeXY; + uniform float in_blurOffset; half4 main(float2 xy) { half4 c = child.eval(xy); - c += child.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), - clamp( in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); - c += child.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), - clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); - c += child.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), - clamp( in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); - c += child.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), - clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); - + c += child.eval(xy + float2(+in_blurOffset, +in_blurOffset)); + c += child.eval(xy + float2(+in_blurOffset, -in_blurOffset)); + c += child.eval(xy + float2(-in_blurOffset, -in_blurOffset)); + c += child.eval(xy + float2(-in_blurOffset, +in_blurOffset)); return half4(c.rgb * 0.2, 1.0); } )"); @@ -90,9 +84,6 @@ sk_sp KawaseBlurFilter::generate(GrRecordingContext* context, const uin SkImageInfo scaledInfo = input->imageInfo().makeWH(std::ceil(blurRect.width() * kInputScale), std::ceil(blurRect.height() * kInputScale)); - const float stepX = radiusByPasses; - const float stepY = radiusByPasses; - // For sampling Skia's API expects the inverse of what logically seems appropriate. In this // case you might expect Translate(blurRect.fLeft, blurRect.fTop) X Scale(kInverseInputScale) // but instead we must do the inverse. @@ -104,20 +95,15 @@ sk_sp KawaseBlurFilter::generate(GrRecordingContext* context, const uin SkRuntimeShaderBuilder blurBuilder(mBlurEffect); blurBuilder.child("child") = input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, blurMatrix); - blurBuilder.uniform("in_blurOffset") = SkV2{stepX * kInputScale, stepY * kInputScale}; - blurBuilder.uniform("in_maxSizeXY") = - SkV2{blurRect.width() * kInputScale, blurRect.height() * kInputScale}; + blurBuilder.uniform("in_blurOffset") = radiusByPasses * kInputScale; sk_sp tmpBlur(blurBuilder.makeImage(context, nullptr, scaledInfo, false)); // And now we'll build our chain of scaled blur stages for (auto i = 1; i < numberOfPasses; i++) { - const float stepScale = (float)i * kInputScale; blurBuilder.child("child") = tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear); - blurBuilder.uniform("in_blurOffset") = SkV2{stepX * stepScale, stepY * stepScale}; - blurBuilder.uniform("in_maxSizeXY") = - SkV2{blurRect.width() * kInputScale, blurRect.height() * kInputScale}; + blurBuilder.uniform("in_blurOffset") = (float) i * radiusByPasses * kInputScale; tmpBlur = blurBuilder.makeImage(context, nullptr, scaledInfo, false); } -- cgit v1.2.3-59-g8ed1b From 9eb02c0ae27754f7230b4cfbd1d34bd837223c6f Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Tue, 19 Oct 2021 14:02:20 -0700 Subject: MotionEvent: Report transformed orientation values Previously, the AXIS_ORIENTATION value reported by MotionEvent was unaffected by the window transform. This meant that whatever value that was generated by InputReader was the value reported to the window. This meant that if the window was rotated or scaled respective to the logical display and the window received an event, it could be the case that the 0 value no longer corresponds with the "up" direction of the window. Now that the input pipeline works in the display panel's coordinate system, we need the orientation value reported by MotionEvent to be affected by the window transform. This CL also refactors the shared logic by which transformed axis values are calculated into a common function. Bug: 179274888 Test: atest libinput_tests Test: atest inputflinger_tests Test: manual with test app and stylus Change-Id: Ibb6f135de47f7c1cbde3c023931a760dfbe08e45 --- include/input/Input.h | 3 + libs/input/Input.cpp | 71 +++++++++------------- libs/input/tests/InputEvent_test.cpp | 22 ++++--- .../input/tests/InputPublisherAndConsumer_test.cpp | 8 ++- 4 files changed, 53 insertions(+), 51 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index 5015e68121..54c71140eb 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -803,6 +803,9 @@ public: static vec2 calculateTransformedXY(uint32_t source, const ui::Transform&, const vec2& xy); + static float calculateTransformedAxisValue(int32_t axis, uint32_t source, const ui::Transform&, + const PointerCoords&); + protected: int32_t mAction; int32_t mActionButton; diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index b4d9ab623c..d018800c90 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -493,44 +493,14 @@ const PointerCoords* MotionEvent::getHistoricalRawPointerCoords( float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const { - const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex); - - if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) { - const vec2 xy = calculateTransformedXY(mSource, mRawTransform, coords->getXYValue()); - static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); - return xy[axis]; - } - - if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) { - const vec2 relativeXy = - transformWithoutTranslation(mRawTransform, - {coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), - coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)}); - return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y; - } - - return coords->getAxisValue(axis); + const PointerCoords& coords = *getHistoricalRawPointerCoords(pointerIndex, historicalIndex); + return calculateTransformedAxisValue(axis, mSource, mRawTransform, coords); } float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const { - const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex); - - if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) { - const vec2 xy = calculateTransformedXY(mSource, mTransform, coords->getXYValue()); - static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); - return xy[axis]; - } - - if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) { - const vec2 relativeXy = - transformWithoutTranslation(mTransform, - {coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), - coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)}); - return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y; - } - - return coords->getAxisValue(axis); + const PointerCoords& coords = *getHistoricalRawPointerCoords(pointerIndex, historicalIndex); + return calculateTransformedAxisValue(axis, mSource, mTransform, coords); } ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const { @@ -569,15 +539,6 @@ void MotionEvent::transform(const std::array& matrix) { ui::Transform newTransform; newTransform.set(matrix); mTransform = newTransform * mTransform; - - // We need to update the AXIS_ORIENTATION value here to maintain the old behavior where the - // orientation angle is not affected by the initial transformation set in the MotionEvent. - std::for_each(mSamplePointerCoords.begin(), mSamplePointerCoords.end(), - [&newTransform](PointerCoords& c) { - float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); - c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, - transformAngle(newTransform, orientation)); - }); } void MotionEvent::applyTransform(const std::array& matrix) { @@ -809,6 +770,30 @@ vec2 MotionEvent::calculateTransformedXY(uint32_t source, const ui::Transform& t : transform.transform(xy); } +float MotionEvent::calculateTransformedAxisValue(int32_t axis, uint32_t source, + const ui::Transform& transform, + const PointerCoords& coords) { + if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) { + const vec2 xy = calculateTransformedXY(source, transform, coords.getXYValue()); + static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); + return xy[axis]; + } + + if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) { + const vec2 relativeXy = + transformWithoutTranslation(transform, + {coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), + coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)}); + return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y; + } + + if (axis == AMOTION_EVENT_AXIS_ORIENTATION) { + return transformAngle(transform, coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); + } + + return coords.getAxisValue(axis); +} + // --- FocusEvent --- void FocusEvent::initialize(int32_t id, bool hasFocus, bool inTouchMode) { diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index caf3a611e2..1b594f142e 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -444,12 +444,19 @@ void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) { ASSERT_EQ(217, event->getToolMinor(0)); ASSERT_EQ(227, event->getToolMinor(1)); - ASSERT_EQ(18, event->getHistoricalOrientation(0, 0)); - ASSERT_EQ(28, event->getHistoricalOrientation(1, 0)); - ASSERT_EQ(118, event->getHistoricalOrientation(0, 1)); - ASSERT_EQ(128, event->getHistoricalOrientation(1, 1)); - ASSERT_EQ(218, event->getOrientation(0)); - ASSERT_EQ(228, event->getOrientation(1)); + // Calculate the orientation after scaling, keeping in mind that an orientation of 0 is "up", + // and the positive y direction is "down". + auto toScaledOrientation = [](float angle) { + const float x = sinf(angle) * X_SCALE; + const float y = -cosf(angle) * Y_SCALE; + return atan2f(x, -y); + }; + ASSERT_EQ(toScaledOrientation(18), event->getHistoricalOrientation(0, 0)); + ASSERT_EQ(toScaledOrientation(28), event->getHistoricalOrientation(1, 0)); + ASSERT_EQ(toScaledOrientation(118), event->getHistoricalOrientation(0, 1)); + ASSERT_EQ(toScaledOrientation(128), event->getHistoricalOrientation(1, 1)); + ASSERT_EQ(toScaledOrientation(218), event->getOrientation(0)); + ASSERT_EQ(toScaledOrientation(228), event->getOrientation(1)); } TEST_F(MotionEventTest, Properties) { @@ -518,6 +525,7 @@ TEST_F(MotionEventTest, OffsetLocation) { TEST_F(MotionEventTest, Scale) { MotionEvent event; initializeEventWithHistory(&event); + const float unscaledOrientation = event.getOrientation(0); event.scale(2.0f); @@ -534,7 +542,7 @@ TEST_F(MotionEventTest, Scale) { ASSERT_EQ(215 * 2, event.getTouchMinor(0)); ASSERT_EQ(216 * 2, event.getToolMajor(0)); ASSERT_EQ(217 * 2, event.getToolMinor(0)); - ASSERT_EQ(218, event.getOrientation(0)); + ASSERT_EQ(unscaledOrientation, event.getOrientation(0)); } TEST_F(MotionEventTest, Parcel) { diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index d09f2ac748..973194c8f6 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -259,7 +259,13 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), motionEvent->getTouchMinor(i)); EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), motionEvent->getToolMajor(i)); EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), motionEvent->getToolMinor(i)); - EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), motionEvent->getOrientation(i)); + + // Calculate the orientation after scaling, keeping in mind that an orientation of 0 is + // "up", and the positive y direction is "down". + const float unscaledOrientation = pc.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); + const float x = sinf(unscaledOrientation) * xScale; + const float y = -cosf(unscaledOrientation) * yScale; + EXPECT_EQ(atan2f(x, -y), motionEvent->getOrientation(i)); } status = mConsumer->sendFinishedSignal(seq, false); -- cgit v1.2.3-59-g8ed1b From 26dacabe028c624af4674537a4347fa56d8de95c Mon Sep 17 00:00:00 2001 From: Robin Lee Date: Mon, 9 Aug 2021 14:31:01 +0200 Subject: Add a GaussianBlurFilter to SkiaRE using Skia blur This is using Skia's native blur algorithm which is a fully-correct blur using separate X/Y convolution passes in a pre-baked shader. The performance is significantly worse than Kawase or dual-filtered Kawase but it sets the high bar for accuracy and the low bar for performance. This can be switched with KawaseBlurFilter by updating the source in SkiaGLRenderEngine to instantiate GaussianBlurFilter instead. Test: atest BlurTests Bug: 185365391 Change-Id: I29fba84e408c75bc8ef7011b6e40f45cb78eabab --- libs/renderengine/Android.bp | 2 + libs/renderengine/skia/SkiaGLRenderEngine.cpp | 5 +- libs/renderengine/skia/filters/BlurFilter.cpp | 124 +++++++++++++++++++++ libs/renderengine/skia/filters/BlurFilter.h | 19 +++- .../skia/filters/GaussianBlurFilter.cpp | 69 ++++++++++++ .../renderengine/skia/filters/GaussianBlurFilter.h | 47 ++++++++ .../renderengine/skia/filters/KawaseBlurFilter.cpp | 77 ------------- libs/renderengine/skia/filters/KawaseBlurFilter.h | 15 --- 8 files changed, 258 insertions(+), 100 deletions(-) create mode 100644 libs/renderengine/skia/filters/BlurFilter.cpp create mode 100644 libs/renderengine/skia/filters/GaussianBlurFilter.cpp create mode 100644 libs/renderengine/skia/filters/GaussianBlurFilter.h diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index 336ff684c1..a62d2b9f85 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -93,6 +93,8 @@ filegroup { "skia/debug/CommonPool.cpp", "skia/debug/SkiaCapture.cpp", "skia/debug/SkiaMemoryReporter.cpp", + "skia/filters/BlurFilter.cpp", + "skia/filters/GaussianBlurFilter.cpp", "skia/filters/KawaseBlurFilter.cpp", "skia/filters/LinearEffect.cpp", "skia/filters/StretchShaderFactory.cpp" diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index e6fb94d1c1..21d56032c2 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -53,6 +53,7 @@ #include "SkBlendMode.h" #include "SkImageInfo.h" #include "filters/BlurFilter.h" +#include "filters/GaussianBlurFilter.h" #include "filters/KawaseBlurFilter.h" #include "filters/LinearEffect.h" #include "log/log_main.h" @@ -804,11 +805,11 @@ void SkiaGLRenderEngine::drawLayersInternal( continue; } if (layer.backgroundBlurRadius > 0 && - layer.backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius) { + layer.backgroundBlurRadius < mBlurFilter->getMaxCrossFadeRadius()) { requiresCompositionLayer = true; } for (auto region : layer.blurRegions) { - if (region.blurRadius < BlurFilter::kMaxCrossFadeRadius) { + if (region.blurRadius < mBlurFilter->getMaxCrossFadeRadius()) { requiresCompositionLayer = true; } } diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp new file mode 100644 index 0000000000..6746e479d2 --- /dev/null +++ b/libs/renderengine/skia/filters/BlurFilter.cpp @@ -0,0 +1,124 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include "BlurFilter.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { +namespace renderengine { +namespace skia { + +static sk_sp createMixEffect() { + SkString mixString(R"( + uniform shader blurredInput; + uniform shader originalInput; + uniform float mixFactor; + + half4 main(float2 xy) { + return half4(mix(originalInput.eval(xy), blurredInput.eval(xy), mixFactor)); + } + )"); + + auto [mixEffect, mixError] = SkRuntimeEffect::MakeForShader(mixString); + if (!mixEffect) { + LOG_ALWAYS_FATAL("RuntimeShader error: %s", mixError.c_str()); + } + return mixEffect; +} + +static SkMatrix getShaderTransform(const SkCanvas* canvas, const SkRect& blurRect, + const float scale) { + // 1. Apply the blur shader matrix, which scales up the blurred surface to its real size + auto matrix = SkMatrix::Scale(scale, scale); + // 2. Since the blurred surface has the size of the layer, we align it with the + // top left corner of the layer position. + matrix.postConcat(SkMatrix::Translate(blurRect.fLeft, blurRect.fTop)); + // 3. Finally, apply the inverse canvas matrix. The snapshot made in the BlurFilter is in the + // original surface orientation. The inverse matrix has to be applied to align the blur + // surface with the current orientation/position of the canvas. + SkMatrix drawInverse; + if (canvas != nullptr && canvas->getTotalMatrix().invert(&drawInverse)) { + matrix.postConcat(drawInverse); + } + return matrix; +} + +BlurFilter::BlurFilter(const float maxCrossFadeRadius) + : mMaxCrossFadeRadius(maxCrossFadeRadius), + mMixEffect(maxCrossFadeRadius > 0 ? createMixEffect() : nullptr) {} + +float BlurFilter::getMaxCrossFadeRadius() const { + return mMaxCrossFadeRadius; +} + +void BlurFilter::drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, + const uint32_t blurRadius, const float blurAlpha, + const SkRect& blurRect, sk_sp blurredImage, + sk_sp input) { + ATRACE_CALL(); + + SkPaint paint; + paint.setAlphaf(blurAlpha); + + const auto blurMatrix = getShaderTransform(canvas, blurRect, kInverseInputScale); + SkSamplingOptions linearSampling(SkFilterMode::kLinear, SkMipmapMode::kNone); + const auto blurShader = blurredImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, + linearSampling, &blurMatrix); + + if (blurRadius < mMaxCrossFadeRadius) { + // For sampling Skia's API expects the inverse of what logically seems appropriate. In this + // case you might expect the matrix to simply be the canvas matrix. + SkMatrix inputMatrix; + if (!canvas->getTotalMatrix().invert(&inputMatrix)) { + ALOGE("matrix was unable to be inverted"); + } + + SkRuntimeShaderBuilder blurBuilder(mMixEffect); + blurBuilder.child("blurredInput") = blurShader; + blurBuilder.child("originalInput") = + input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linearSampling, + inputMatrix); + blurBuilder.uniform("mixFactor") = blurRadius / mMaxCrossFadeRadius; + + paint.setShader(blurBuilder.makeShader(nullptr, true)); + } else { + paint.setShader(blurShader); + } + + if (effectRegion.isRect()) { + if (blurAlpha == 1.0f) { + paint.setBlendMode(SkBlendMode::kSrc); + } + canvas->drawRect(effectRegion.rect(), paint); + } else { + paint.setAntiAlias(true); + canvas->drawRRect(effectRegion, paint); + } +} + +} // namespace skia +} // namespace renderengine +} // namespace android diff --git a/libs/renderengine/skia/filters/BlurFilter.h b/libs/renderengine/skia/filters/BlurFilter.h index 1beadee092..9cddc757fc 100644 --- a/libs/renderengine/skia/filters/BlurFilter.h +++ b/libs/renderengine/skia/filters/BlurFilter.h @@ -33,11 +33,8 @@ public: static constexpr float kInputScale = 0.25f; // Downsample scale factor used to improve performance static constexpr float kInverseInputScale = 1.0f / kInputScale; - // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited - // image, up to this radius. - static constexpr float kMaxCrossFadeRadius = 10.0f; - explicit BlurFilter(){} + explicit BlurFilter(float maxCrossFadeRadius = 10.0f); virtual ~BlurFilter(){} // Execute blur, saving it to a texture @@ -54,10 +51,20 @@ public: * @param blurredImage down-sampled blurred content that was produced by the generate() method * @param input original unblurred input that is used to crossfade with the blurredImage */ - virtual void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, + void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, const uint32_t blurRadius, const float blurAlpha, const SkRect& blurRect, sk_sp blurredImage, - sk_sp input) = 0; + sk_sp input); + + float getMaxCrossFadeRadius() const; + +private: + // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited + // image, up to this radius. + const float mMaxCrossFadeRadius; + + // Optional blend used for crossfade only if mMaxCrossFadeRadius > 0 + const sk_sp mMixEffect; }; } // namespace skia diff --git a/libs/renderengine/skia/filters/GaussianBlurFilter.cpp b/libs/renderengine/skia/filters/GaussianBlurFilter.cpp new file mode 100644 index 0000000000..55867a95cc --- /dev/null +++ b/libs/renderengine/skia/filters/GaussianBlurFilter.cpp @@ -0,0 +1,69 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include "GaussianBlurFilter.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { +namespace renderengine { +namespace skia { + +// This constant approximates the scaling done in the software path's +// "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)). +static const float BLUR_SIGMA_SCALE = 0.57735f; + +GaussianBlurFilter::GaussianBlurFilter(): BlurFilter(/* maxCrossFadeRadius= */ 0.0f) {} + +sk_sp GaussianBlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius, + const sk_sp input, const SkRect& blurRect) + const { + // Create blur surface with the bit depth and colorspace of the original surface + SkImageInfo scaledInfo = input->imageInfo().makeWH(std::ceil(blurRect.width() * kInputScale), + std::ceil(blurRect.height() * kInputScale)); + sk_sp surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, scaledInfo); + + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); + paint.setImageFilter(SkImageFilters::Blur( + blurRadius * kInputScale * BLUR_SIGMA_SCALE, + blurRadius * kInputScale * BLUR_SIGMA_SCALE, + SkTileMode::kClamp, nullptr)); + + surface->getCanvas()->drawImageRect( + input, + blurRect, + SkRect::MakeWH(scaledInfo.width(), scaledInfo.height()), + SkSamplingOptions{SkFilterMode::kLinear, SkMipmapMode::kNone}, + &paint, + SkCanvas::SrcRectConstraint::kFast_SrcRectConstraint); + return surface->makeImageSnapshot(); +} + +} // namespace skia +} // namespace renderengine +} // namespace android diff --git a/libs/renderengine/skia/filters/GaussianBlurFilter.h b/libs/renderengine/skia/filters/GaussianBlurFilter.h new file mode 100644 index 0000000000..a4febd2257 --- /dev/null +++ b/libs/renderengine/skia/filters/GaussianBlurFilter.h @@ -0,0 +1,47 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "BlurFilter.h" +#include +#include +#include +#include + +using namespace std; + +namespace android { +namespace renderengine { +namespace skia { + +/** + * This is an implementation of a Gaussian blur using Skia's built-in GaussianBlur filter. + */ +class GaussianBlurFilter: public BlurFilter { +public: + explicit GaussianBlurFilter(); + virtual ~GaussianBlurFilter(){} + + // Execute blur, saving it to a texture + sk_sp generate(GrRecordingContext* context, const uint32_t radius, + const sk_sp blurInput, const SkRect& blurRect) const override; + +}; + +} // namespace skia +} // namespace renderengine +} // namespace android diff --git a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp index e3a0e58649..bfde06fd9a 100644 --- a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp +++ b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp @@ -52,22 +52,6 @@ KawaseBlurFilter::KawaseBlurFilter(): BlurFilter() { LOG_ALWAYS_FATAL("RuntimeShader error: %s", error.c_str()); } mBlurEffect = std::move(blurEffect); - - SkString mixString(R"( - uniform shader blurredInput; - uniform shader originalInput; - uniform float mixFactor; - - half4 main(float2 xy) { - return half4(mix(originalInput.eval(xy), blurredInput.eval(xy), mixFactor)); - } - )"); - - auto [mixEffect, mixError] = SkRuntimeEffect::MakeForShader(mixString); - if (!mixEffect) { - LOG_ALWAYS_FATAL("RuntimeShader error: %s", mixError.c_str()); - } - mMixEffect = std::move(mixEffect); } sk_sp KawaseBlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius, @@ -110,67 +94,6 @@ sk_sp KawaseBlurFilter::generate(GrRecordingContext* context, const uin return tmpBlur; } -static SkMatrix getShaderTransform(const SkCanvas* canvas, const SkRect& blurRect, float scale) { - // 1. Apply the blur shader matrix, which scales up the blured surface to its real size - auto matrix = SkMatrix::Scale(scale, scale); - // 2. Since the blurred surface has the size of the layer, we align it with the - // top left corner of the layer position. - matrix.postConcat(SkMatrix::Translate(blurRect.fLeft, blurRect.fTop)); - // 3. Finally, apply the inverse canvas matrix. The snapshot made in the BlurFilter is in the - // original surface orientation. The inverse matrix has to be applied to align the blur - // surface with the current orientation/position of the canvas. - SkMatrix drawInverse; - if (canvas != nullptr && canvas->getTotalMatrix().invert(&drawInverse)) { - matrix.postConcat(drawInverse); - } - return matrix; -} - -void KawaseBlurFilter::drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, - const uint32_t blurRadius, const float blurAlpha, - const SkRect& blurRect, sk_sp blurredImage, - sk_sp input) { - ATRACE_CALL(); - - SkPaint paint; - paint.setAlphaf(blurAlpha); - - const auto blurMatrix = getShaderTransform(canvas, blurRect, kInverseInputScale); - SkSamplingOptions linearSampling(SkFilterMode::kLinear, SkMipmapMode::kNone); - const auto blurShader = blurredImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, - linearSampling, &blurMatrix); - - if (blurRadius < kMaxCrossFadeRadius) { - // For sampling Skia's API expects the inverse of what logically seems appropriate. In this - // case you might expect the matrix to simply be the canvas matrix. - SkMatrix inputMatrix; - if (!canvas->getTotalMatrix().invert(&inputMatrix)) { - ALOGE("matrix was unable to be inverted"); - } - - SkRuntimeShaderBuilder blurBuilder(mMixEffect); - blurBuilder.child("blurredInput") = blurShader; - blurBuilder.child("originalInput") = - input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linearSampling, - inputMatrix); - blurBuilder.uniform("mixFactor") = blurRadius / kMaxCrossFadeRadius; - - paint.setShader(blurBuilder.makeShader(nullptr, true)); - } else { - paint.setShader(blurShader); - } - - if (effectRegion.isRect()) { - if (blurAlpha == 1.0f) { - paint.setBlendMode(SkBlendMode::kSrc); - } - canvas->drawRect(effectRegion.rect(), paint); - } else { - paint.setAntiAlias(true); - canvas->drawRRect(effectRegion, paint); - } -} - } // namespace skia } // namespace renderengine } // namespace android diff --git a/libs/renderengine/skia/filters/KawaseBlurFilter.h b/libs/renderengine/skia/filters/KawaseBlurFilter.h index d2731e3585..0ac5ac8866 100644 --- a/libs/renderengine/skia/filters/KawaseBlurFilter.h +++ b/libs/renderengine/skia/filters/KawaseBlurFilter.h @@ -45,23 +45,8 @@ public: sk_sp generate(GrRecordingContext* context, const uint32_t radius, const sk_sp blurInput, const SkRect& blurRect) const override; - /** - * Draw the blurred content (from the generate method) into the canvas. - * @param canvas is the destination/output for the blur - * @param effectRegion the RoundRect in canvas coordinates that determines the blur coverage - * @param blurRadius radius of the blur used to determine the intensity of the crossfade effect - * @param blurAlpha alpha value applied to the effectRegion when the blur is drawn - * @param blurRect bounds of the blurredImage translated into canvas coordinates - * @param blurredImage down-sampled blurred content that was produced by the generate() method - * @param input original unblurred input that is used to crossfade with the blurredImage - */ - void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, const uint32_t blurRadius, - const float blurAlpha, const SkRect& blurRect, sk_sp blurredImage, - sk_sp input) override; - private: sk_sp mBlurEffect; - sk_sp mMixEffect; }; } // namespace skia -- cgit v1.2.3-59-g8ed1b From 18f8e9fb49b7efe59317d111fa3243056033954a Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Mon, 25 Oct 2021 13:20:59 -0700 Subject: Add @defgroup for ADataSpace file Bug: 148875303 Test: able to see ADataSpace in NDK API preview Change-Id: I8914e6d84da2dff8b52e6375440e97f8f3f8ee98 --- libs/nativewindow/include/android/data_space.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h index a299488120..0565f424f2 100644 --- a/libs/nativewindow/include/android/data_space.h +++ b/libs/nativewindow/include/android/data_space.h @@ -14,6 +14,13 @@ * limitations under the License. */ +/** + * @defgroup ADataSpace Data Space + * + * ADataSpace describes how to interpret colors. + * @{ + */ + /** * @file data_space.h */ @@ -517,3 +524,5 @@ enum ADataSpace { __END_DECLS #endif // ANDROID_DATA_SPACE_H + +/** @} */ -- cgit v1.2.3-59-g8ed1b From b3307ee4952e372da4bfd57b71085c3a55ade5f0 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Thu, 14 Oct 2021 10:57:37 +0000 Subject: Add logs to trace no window touched and cancel event To clarify some unresponsive touch problems, we have to know if the event has really sent from firmware and some window could be touched or it's dropped because of cancel. - Add the explicit log where we did not really find a touched window. - Add input_cacnel event log to identify the reason. Test: atest inputflinger_tests Bug: 201647070 Bug: 200837970 Change-Id: I17b1de6c96ddc11d2ca2efd00e30e00847b98406 --- services/inputflinger/dispatcher/EventLogTags.logtags | 1 + services/inputflinger/dispatcher/InputDispatcher.cpp | 12 ++++++++++++ services/inputflinger/tests/InputDispatcher_test.cpp | 11 +++++++++++ 3 files changed, 24 insertions(+) diff --git a/services/inputflinger/dispatcher/EventLogTags.logtags b/services/inputflinger/dispatcher/EventLogTags.logtags index 283646793c..2c5fe213fb 100644 --- a/services/inputflinger/dispatcher/EventLogTags.logtags +++ b/services/inputflinger/dispatcher/EventLogTags.logtags @@ -37,6 +37,7 @@ 62000 input_interaction (windows|4) 62001 input_focus (window|3),(reason|3) +62003 input_cancel (window|3),(reason|3) # NOTE - the range 1000000-2000000 is reserved for partners and others who # want to define their own log tags without conflicting with the core platform. \ No newline at end of file diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index ea5799a4ce..176cf8943a 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -153,6 +153,7 @@ constexpr size_t RECENT_QUEUE_MAX_SIZE = 10; // Event log tags. See EventLogTags.logtags for reference constexpr int LOGTAG_INPUT_INTERACTION = 62000; constexpr int LOGTAG_INPUT_FOCUS = 62001; +constexpr int LOGTAG_INPUT_CANCEL = 62003; inline nsecs_t now() { return systemTime(SYSTEM_TIME_MONOTONIC); @@ -2077,6 +2078,8 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( // Handle the case where we did not find a window. if (newTouchedWindowHandle == nullptr) { + ALOGD("No new touched window at (%" PRId32 ", %" PRId32 ") in display %" PRId32, x, y, + displayId); // Try to assign the pointer to the first foreground window we find, if there is one. newTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle(); } @@ -2870,6 +2873,11 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, if (!splitMotionEntry) { return; // split event was dropped } + if (splitMotionEntry->action == AMOTION_EVENT_ACTION_CANCEL) { + std::string reason = std::string("reason=pointer cancel on split window"); + android_log_event_list(LOGTAG_INPUT_CANCEL) + << connection->getInputChannelName().c_str() << reason << LOG_ID_EVENTS; + } if (DEBUG_FOCUS) { ALOGD("channel '%s' ~ Split motion event.", connection->getInputChannelName().c_str()); @@ -3575,6 +3583,10 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( options.mode); } + std::string reason = std::string("reason=").append(options.reason); + android_log_event_list(LOGTAG_INPUT_CANCEL) + << connection->getInputChannelName().c_str() << reason << LOG_ID_EVENTS; + InputTarget target; sp windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken()); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 1879cecb5c..ba0ce95458 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -2841,6 +2841,17 @@ TEST_F(InputDispatcherTest, GestureMonitor_NoWindowTransform) { ASSERT_EQ(ui::Transform(), event->getTransform()); } +TEST_F(InputDispatcherTest, GestureMonitor_NoWindow) { + std::shared_ptr application = std::make_shared(); + FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT, + true /*isGestureMonitor*/); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); +} + TEST_F(InputDispatcherTest, TestMoveEvent) { std::shared_ptr application = std::make_shared(); sp window = -- cgit v1.2.3-59-g8ed1b From dbc93d7ae8c7660aab002bcec2ade86daad7c172 Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Tue, 26 Oct 2021 18:28:57 -0700 Subject: Save Layer instead of Handle to LayerCreatedState Saving Handle to LayerCreatedState can lead to the destruction of Handle when handleLayerCreatedLocked returns if the client side releases the Handle before that. That destruction will attempt to acquire mStateLock in the main thread again and lead to a deadlock. Not saving Handle to LayerCreatedState will avoid Handle being destroyed in the main thread. The destruction of Layer in the main thread is OK. To make that happen I moved the final resolution of addToRoot to createLayer as well because the treatments for invalid parentHandle and invalid parentLayer are different. Bug: 204204635 Bug: 202621651 Test: atest SurfaceFlinger_test Test: atest libsurfaceflinger_unittest Change-Id: I0854203c0949302d7f514d34b956eb7ae976c51f --- services/surfaceflinger/SurfaceFlinger.cpp | 35 +++++++++++++++--------------- services/surfaceflinger/SurfaceFlinger.h | 15 +++++-------- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8d7221c1dc..48c3c108c1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3356,8 +3356,7 @@ bool SurfaceFlinger::latchBuffers() { status_t SurfaceFlinger::addClientLayer(const sp& client, const sp& handle, const sp& gbc, const sp& lbc, - const sp& parentHandle, - const sp& parentLayer, bool addToRoot, + const wp& parent, bool addToRoot, uint32_t* outTransformHint) { if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) { ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(), @@ -3369,7 +3368,7 @@ status_t SurfaceFlinger::addClientLayer(const sp& client, const sp states; @@ -4227,7 +4226,7 @@ status_t SurfaceFlinger::mirrorLayer(const sp& client, const sp } *outLayerId = mirrorLayer->sequence; - return addClientLayer(client, *outHandle, nullptr, mirrorLayer, nullptr, nullptr, false, + return addClientLayer(client, *outHandle, nullptr, mirrorLayer, nullptr, false, nullptr /* outTransformHint */); } @@ -4296,8 +4295,15 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie } bool addToRoot = callingThreadHasUnscopedSurfaceFlingerAccess(); - result = addClientLayer(client, *handle, *gbp, layer, parentHandle, parentLayer, addToRoot, - outTransformHint); + wp parent(parentHandle != nullptr ? fromHandle(parentHandle) : parentLayer); + if (parentHandle != nullptr && parent == nullptr) { + ALOGE("Invalid parent handle %p.", parentHandle.get()); + addToRoot = false; + } + if (parentLayer != nullptr) { + addToRoot = false; + } + result = addClientLayer(client, *handle, *gbp, layer, parent, addToRoot, outTransformHint); if (result != NO_ERROR) { return result; } @@ -6777,11 +6783,11 @@ void TransactionState::traverseStatesWithBuffers( } void SurfaceFlinger::setLayerCreatedState(const sp& handle, const wp& layer, - const sp& parent, const wp parentLayer, - const wp& producer, bool addToRoot) { + const wp parent, const wp& producer, + bool addToRoot) { Mutex::Autolock lock(mCreatedLayersLock); mCreatedLayers[handle->localBinder()] = - std::make_unique(layer, parent, parentLayer, producer, addToRoot); + std::make_unique(layer, parent, producer, addToRoot); } auto SurfaceFlinger::getLayerCreatedState(const sp& handle) { @@ -6819,19 +6825,14 @@ sp SurfaceFlinger::handleLayerCreatedLocked(const sp& handle) { } sp parent; - bool allowAddRoot = state->addToRoot; if (state->initialParent != nullptr) { - parent = fromHandle(state->initialParent).promote(); + parent = state->initialParent.promote(); if (parent == nullptr) { - ALOGE("Invalid parent %p", state->initialParent.get()); - allowAddRoot = false; + ALOGE("Invalid parent %p", state->initialParent.unsafe_get()); } - } else if (state->initialParentLayer != nullptr) { - parent = state->initialParentLayer.promote(); - allowAddRoot = false; } - if (parent == nullptr && allowAddRoot) { + if (parent == nullptr && state->addToRoot) { layer->setIsAtRoot(true); mCurrentState.layersSortedByZ.add(layer); } else if (parent == nullptr) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 276c7f6bfe..a1e431b54f 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -795,8 +795,8 @@ private: // add a layer to SurfaceFlinger status_t addClientLayer(const sp& client, const sp& handle, const sp& gbc, const sp& lbc, - const sp& parentHandle, const sp& parentLayer, - bool addToRoot, uint32_t* outTransformHint); + const wp& parentLayer, bool addToRoot, + uint32_t* outTransformHint); // Traverse through all the layers and compute and cache its bounds. void computeLayerBounds(); @@ -1345,18 +1345,16 @@ private: GUARDED_BY(mStateLock); mutable Mutex mCreatedLayersLock; struct LayerCreatedState { - LayerCreatedState(const wp& layer, const sp& parent, - const wp parentLayer, const wp& producer, bool addToRoot) + LayerCreatedState(const wp& layer, const wp parent, + const wp& producer, bool addToRoot) : layer(layer), initialParent(parent), - initialParentLayer(parentLayer), initialProducer(producer), addToRoot(addToRoot) {} wp layer; // Indicates the initial parent of the created layer, only used for creating layer in // SurfaceFlinger. If nullptr, it may add the created layer into the current root layers. - sp initialParent; - wp initialParentLayer; + wp initialParent; // Indicates the initial graphic buffer producer of the created layer, only used for // creating layer in SurfaceFlinger. wp initialProducer; @@ -1370,8 +1368,7 @@ private: // thread. std::unordered_map> mCreatedLayers; void setLayerCreatedState(const sp& handle, const wp& layer, - const sp& parent, const wp parentLayer, - const wp& producer, bool addToRoot); + const wp parent, const wp& producer, bool addToRoot); auto getLayerCreatedState(const sp& handle); sp handleLayerCreatedLocked(const sp& handle) REQUIRES(mStateLock); -- cgit v1.2.3-59-g8ed1b From d712ad3e221a1a9442843a206b55a1771be884e5 Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Wed, 27 Oct 2021 13:44:22 -0700 Subject: Avoid adding to root when parent is destroyed The move of addToRoot resolution left a behavior change that we now would allow the layer being added to root if its initial parent is destroyed between queuing the layer creation transaction and actual handling of it in the main thread. Bug: 204204635 Test: atest SurfaceFlinger_test Test: atest libsurfaceflinger_test Change-Id: I2f5b30cbe6fc579540a673af22ad41e248ae25c9 --- services/surfaceflinger/SurfaceFlinger.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 48c3c108c1..cc9e1f8934 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -6825,14 +6825,16 @@ sp SurfaceFlinger::handleLayerCreatedLocked(const sp& handle) { } sp parent; + bool addToRoot = state->addToRoot; if (state->initialParent != nullptr) { parent = state->initialParent.promote(); if (parent == nullptr) { ALOGE("Invalid parent %p", state->initialParent.unsafe_get()); + addToRoot = false; } } - if (parent == nullptr && state->addToRoot) { + if (parent == nullptr && addToRoot) { layer->setIsAtRoot(true); mCurrentState.layersSortedByZ.add(layer); } else if (parent == nullptr) { -- cgit v1.2.3-59-g8ed1b From 0e54231ffc9152ec3347eff4c450dadb297d6174 Mon Sep 17 00:00:00 2001 From: Neharika Jali Date: Mon, 25 Oct 2021 06:41:24 +0000 Subject: Eliminating the concept of reserved cache Bug: 203649806 Test: atest installd_cache_test Ignore-AOSP-First: This CL is to be submitted in a topic aimed for T release Change-Id: I9e861747c745f711f8d9a1c3c04ef1168a64b415 --- cmds/installd/InstalldNativeService.cpp | 8 +---- cmds/installd/InstalldNativeService.h | 2 +- cmds/installd/binder/android/os/IInstalld.aidl | 3 +- cmds/installd/tests/installd_cache_test.cpp | 43 +++++++++++++++++++++----- 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 157d259a9b..bb83db5b59 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -1344,7 +1344,7 @@ binder::Status InstalldNativeService::destroyUserData(const std::optional& uuid, - int64_t targetFreeBytes, int64_t cacheReservedBytes, int32_t flags) { + int64_t targetFreeBytes, int32_t flags) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); std::lock_guard lock(mLock); @@ -1447,12 +1447,6 @@ binder::Status InstalldNativeService::freeCache(const std::optional break; } - // Only keep clearing when we haven't pushed into reserved area - if (cacheReservedBytes > 0 && cleared >= (cacheTotal - cacheReservedBytes)) { - LOG(DEBUG) << "Refusing to clear cached data in reserved space"; - break; - } - // Find the best tracker to work with; this might involve swapping // if the active tracker is no longer the most over quota bool nextBetter = active && !queue.empty() diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index ae257dfcf8..e156b5e77c 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -144,7 +144,7 @@ public: binder::Status rmPackageDir(const std::string& packageDir); binder::Status freeCache(const std::optional& uuid, int64_t targetFreeBytes, - int64_t cacheReservedBytes, int32_t flags); + int32_t flags); binder::Status linkNativeLibraryDirectory(const std::optional& uuid, const std::string& packageName, const std::string& nativeLibPath32, int32_t userId); binder::Status createOatDir(const std::string& oatDir, const std::string& instructionSet); diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index 637a9f2171..9c51ff749d 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -86,8 +86,7 @@ interface IInstalld { void destroyProfileSnapshot(@utf8InCpp String packageName, @utf8InCpp String profileName); void rmPackageDir(@utf8InCpp String packageDir); - void freeCache(@nullable @utf8InCpp String uuid, long targetFreeBytes, - long cacheReservedBytes, int flags); + void freeCache(@nullable @utf8InCpp String uuid, long targetFreeBytes, int flags); void linkNativeLibraryDirectory(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName, @utf8InCpp String nativeLibPath32, int userId); void createOatDir(@utf8InCpp String oatDir, @utf8InCpp String instructionSet); diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp index 863cdfe55b..9a1e17eb20 100644 --- a/cmds/installd/tests/installd_cache_test.cpp +++ b/cmds/installd/tests/installd_cache_test.cpp @@ -145,7 +145,7 @@ TEST_F(CacheTest, FreeCache_All) { EXPECT_EQ(0, exists("com.example/cache/foo/one")); EXPECT_EQ(0, exists("com.example/cache/foo/two")); - service->freeCache(testUuid, kTbInBytes, 0, + service->freeCache(testUuid, kTbInBytes, FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA); EXPECT_EQ(0, exists("com.example/normal")); @@ -153,6 +153,33 @@ TEST_F(CacheTest, FreeCache_All) { EXPECT_EQ(-1, exists("com.example/cache/foo/two")); } +TEST_F(CacheTest, FreeCache_NonAggressive) { + LOG(INFO) << "FreeCache_NonAggressive"; + + mkdir("com.example"); + touch("com.example/normal", 1 * kMbInBytes, 60); + mkdir("com.example/cache"); + mkdir("com.example/cache/foo"); + touch("com.example/cache/foo/one", 65 * kMbInBytes, 60); + touch("com.example/cache/foo/two", 2 * kMbInBytes, 120); + + EXPECT_EQ(0, exists("com.example/normal")); + EXPECT_EQ(0, exists("com.example/cache/foo/one")); + EXPECT_EQ(0, exists("com.example/cache/foo/two")); + + service->freeCache(testUuid, kTbInBytes, FLAG_FREE_CACHE_V2); + + EXPECT_EQ(0, exists("com.example/normal")); + EXPECT_EQ(-1, exists("com.example/cache/foo/one")); + EXPECT_EQ(0, exists("com.example/cache/foo/two")); + + service->freeCache(testUuid, kTbInBytes, FLAG_FREE_CACHE_V2); + + EXPECT_EQ(0, exists("com.example/normal")); + EXPECT_EQ(-1, exists("com.example/cache/foo/one")); + EXPECT_EQ(0, exists("com.example/cache/foo/two")); +} + TEST_F(CacheTest, FreeCache_Age) { LOG(INFO) << "FreeCache_Age"; @@ -162,13 +189,13 @@ TEST_F(CacheTest, FreeCache_Age) { touch("com.example/cache/foo/one", kMbInBytes, 60); touch("com.example/cache/foo/two", kMbInBytes, 120); - service->freeCache(testUuid, free() + kKbInBytes, 0, + service->freeCache(testUuid, free() + kKbInBytes, FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA); EXPECT_EQ(-1, exists("com.example/cache/foo/one")); EXPECT_EQ(0, exists("com.example/cache/foo/two")); - service->freeCache(testUuid, free() + kKbInBytes, 0, + service->freeCache(testUuid, free() + kKbInBytes, FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA); EXPECT_EQ(-1, exists("com.example/cache/foo/one")); @@ -196,7 +223,7 @@ TEST_F(CacheTest, FreeCache_Tombstone) { EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar1")); EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar2")); - service->freeCache(testUuid, kTbInBytes, 0, + service->freeCache(testUuid, kTbInBytes, FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA); EXPECT_EQ(-1, exists("com.example/cache/foo/foo1")); @@ -218,7 +245,7 @@ TEST_F(CacheTest, FreeCache_Group) { setxattr("com.example/cache/foo", "user.cache_group"); - service->freeCache(testUuid, free() + kKbInBytes, 0, + service->freeCache(testUuid, free() + kKbInBytes, FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA); EXPECT_EQ(-1, exists("com.example/cache/foo/foo1")); @@ -263,7 +290,7 @@ TEST_F(CacheTest, FreeCache_GroupTombstone) { setxattr("com.example/cache/tomb", "user.cache_tombstone"); setxattr("com.example/cache/tomb/group", "user.cache_group"); - service->freeCache(testUuid, free() + kKbInBytes, 0, + service->freeCache(testUuid, free() + kKbInBytes, FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA); EXPECT_EQ(kMbInBytes, size("com.example/cache/group/file1")); @@ -284,7 +311,7 @@ TEST_F(CacheTest, FreeCache_GroupTombstone) { EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1")); EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2")); - service->freeCache(testUuid, free() + kKbInBytes, 0, + service->freeCache(testUuid, free() + kKbInBytes, FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA); EXPECT_EQ(-1, size("com.example/cache/group/file1")); @@ -305,7 +332,7 @@ TEST_F(CacheTest, FreeCache_GroupTombstone) { EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1")); EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2")); - service->freeCache(testUuid, kTbInBytes, 0, + service->freeCache(testUuid, kTbInBytes, FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA); EXPECT_EQ(-1, size("com.example/cache/group/file1")); -- cgit v1.2.3-59-g8ed1b From 8fcfa66dbb2d75b8bfeaa5168aebe94b93fd8229 Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Tue, 12 Oct 2021 11:33:30 -0400 Subject: sf-latency: Write a benchmark for RenderEngine Bug: 193240340 Test: mmma -j frameworks/native/libs/renderengine/bench/ && adb push out/.../librenderengine_bench /data/.../librenderengine_bench && adb shell /data/.../librenderengine_bench Write a benchmark using Google-Benchmark to track the performance of RenderEngine. RenderEngineBench.cpp: - Contains the benchmarks to run. - Write a helper function that times calls to RenderEngine::drawLayers. - Write a single benchmark that times drawing a mock homescreen plus a blur layer, using a blur radius used in practice. Decode the homescreen into a buffer with CPU support, and then copy it to one without, which better represents actual use. - Use RenderEngineType to determine which subclass to benchmark. The only existing benchmark uses SKIA_GL, since we intend to time just drawLayers, but future benchmarks will want to time threading aspects with SKIA_GL_THREADED, and we may add more RenderEngineTypes in the future. Codec.cpp: - Write methods for decoding and encoding a buffer. Flags.cpp: - Extra flags that can be passed to the executable. - --save allows encoding the result to a file to verify it looks as intended. - parse --help to describe --save and any future flags specific to RenderEngineBench. RenderEngineBench.h: - header file for methods used across cpp files. Use a single common header since otherwise we would have several small headers. homescreen.png: - Mock homescreen to draw in drawLayers Change-Id: I81a1a8a30a1c20985bbf066d2ba4d5f1fd1f6dc3 --- libs/renderengine/benchmark/Android.bp | 54 +++++ libs/renderengine/benchmark/Codec.cpp | 136 +++++++++++ libs/renderengine/benchmark/Flags.cpp | 48 ++++ libs/renderengine/benchmark/RenderEngineBench.cpp | 252 +++++++++++++++++++++ libs/renderengine/benchmark/RenderEngineBench.h | 65 ++++++ libs/renderengine/benchmark/main.cpp | 32 +++ .../benchmark/resources/homescreen.png | Bin 0 -> 4907729 bytes 7 files changed, 587 insertions(+) create mode 100644 libs/renderengine/benchmark/Android.bp create mode 100644 libs/renderengine/benchmark/Codec.cpp create mode 100644 libs/renderengine/benchmark/Flags.cpp create mode 100644 libs/renderengine/benchmark/RenderEngineBench.cpp create mode 100644 libs/renderengine/benchmark/RenderEngineBench.h create mode 100644 libs/renderengine/benchmark/main.cpp create mode 100644 libs/renderengine/benchmark/resources/homescreen.png diff --git a/libs/renderengine/benchmark/Android.bp b/libs/renderengine/benchmark/Android.bp new file mode 100644 index 0000000000..5968399544 --- /dev/null +++ b/libs/renderengine/benchmark/Android.bp @@ -0,0 +1,54 @@ +// Copyright 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + +cc_benchmark { + name: "librenderengine_bench", + defaults: ["skia_deps", "surfaceflinger_defaults"], + srcs: [ + "main.cpp", + "Codec.cpp", + "Flags.cpp", + "RenderEngineBench.cpp", + ], + static_libs: [ + "librenderengine", + ], + cflags: [ + "-DLOG_TAG=\"RenderEngineBench\"", + ], + + shared_libs: [ + "libbase", + "libcutils", + "libjnigraphics", + "libgui", + "liblog", + "libnativewindow", + "libprocessgroup", + "libsync", + "libui", + "libutils", + ], + + data: [ "resources/*"], +} diff --git a/libs/renderengine/benchmark/Codec.cpp b/libs/renderengine/benchmark/Codec.cpp new file mode 100644 index 0000000000..80e4fc4432 --- /dev/null +++ b/libs/renderengine/benchmark/Codec.cpp @@ -0,0 +1,136 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace android; +using namespace android::renderengine; + +namespace { +struct DecoderDeleter { + void operator()(AImageDecoder* decoder) { AImageDecoder_delete(decoder); } +}; + +using AutoDecoderDeleter = std::unique_ptr; + +bool ok(int aImageDecoderResult, const char* path, const char* method) { + if (aImageDecoderResult == ANDROID_IMAGE_DECODER_SUCCESS) { + return true; + } + + ALOGE("Failed AImageDecoder_%s on '%s' with error '%s'", method, path, + AImageDecoder_resultToString(aImageDecoderResult)); + return false; +} +} // namespace + +namespace renderenginebench { + +void decode(const char* path, const sp& buffer) { + base::unique_fd fd{open(path, O_RDONLY)}; + if (fd.get() < 0) { + ALOGE("Failed to open %s", path); + return; + } + + AImageDecoder* decoder{nullptr}; + auto result = AImageDecoder_createFromFd(fd.get(), &decoder); + if (!ok(result, path, "createFromFd")) { + return; + } + + AutoDecoderDeleter deleter(decoder); + + LOG_ALWAYS_FATAL_IF(buffer->getWidth() <= 0 || buffer->getHeight() <= 0, + "Impossible buffer size!"); + auto width = static_cast(buffer->getWidth()); + auto height = static_cast(buffer->getHeight()); + result = AImageDecoder_setTargetSize(decoder, width, height); + if (!ok(result, path, "setTargetSize")) { + return; + } + + void* pixels{nullptr}; + int32_t stride{0}; + if (auto status = buffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, &pixels, + nullptr /*outBytesPerPixel*/, &stride); + status < 0) { + ALOGE("Failed to lock pixels!"); + return; + } + + result = AImageDecoder_decodeImage(decoder, pixels, static_cast(stride), + static_cast(stride * height)); + if (auto status = buffer->unlock(); status < 0) { + ALOGE("Failed to unlock pixels!"); + } + + // For the side effect of logging. + (void)ok(result, path, "decodeImage"); +} + +void encodeToJpeg(const char* path, const sp& buffer) { + base::unique_fd fd{open(path, O_WRONLY | O_CREAT, S_IWUSR)}; + if (fd.get() < 0) { + ALOGE("Failed to open %s", path); + return; + } + + void* pixels{nullptr}; + int32_t stride{0}; + if (auto status = buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, &pixels, + nullptr /*outBytesPerPixel*/, &stride); + status < 0) { + ALOGE("Failed to lock pixels!"); + return; + } + + AndroidBitmapInfo info{ + .width = buffer->getWidth(), + .height = buffer->getHeight(), + .stride = static_cast(stride), + .format = ANDROID_BITMAP_FORMAT_RGBA_8888, + .flags = ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE, + }; + int result = AndroidBitmap_compress(&info, ADATASPACE_SRGB, pixels, + ANDROID_BITMAP_COMPRESS_FORMAT_JPEG, 80, &fd, + [](void* fdPtr, const void* data, size_t size) -> bool { + const ssize_t bytesWritten = + write(reinterpret_cast(fdPtr) + ->get(), + data, size); + return bytesWritten > 0 && + static_cast(bytesWritten) == size; + }); + if (result == ANDROID_BITMAP_RESULT_SUCCESS) { + ALOGD("Successfully encoded to '%s'", path); + } else { + ALOGE("Failed to encode to %s with error %d", path, result); + } + + if (auto status = buffer->unlock(); status < 0) { + ALOGE("Failed to unlock pixels!"); + } +} + +} // namespace renderenginebench diff --git a/libs/renderengine/benchmark/Flags.cpp b/libs/renderengine/benchmark/Flags.cpp new file mode 100644 index 0000000000..c5d51563f4 --- /dev/null +++ b/libs/renderengine/benchmark/Flags.cpp @@ -0,0 +1,48 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace { +bool gSave = false; +} + +namespace renderenginebench { + +void parseFlagsForHelp(int argc, char** argv) { + for (int i = 0; i < argc; i++) { + if (!strcmp(argv[i], "--help")) { + printf("RenderEngineBench-specific flags:\n"); + printf("[--save]: Save the output to the device to confirm drawing result.\n"); + break; + } + } +} + +void parseFlags(int argc, char** argv) { + for (int i = 0; i < argc; i++) { + if (!strcmp(argv[i], "--save")) { + gSave = true; + } + } +} + +bool save() { + return gSave; +} +} // namespace renderenginebench diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp new file mode 100644 index 0000000000..719b855348 --- /dev/null +++ b/libs/renderengine/benchmark/RenderEngineBench.cpp @@ -0,0 +1,252 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace android; +using namespace android::renderengine; + +/////////////////////////////////////////////////////////////////////////////// +// Helpers for Benchmark::Apply +/////////////////////////////////////////////////////////////////////////////// + +std::string RenderEngineTypeName(RenderEngine::RenderEngineType type) { + switch (type) { + case RenderEngine::RenderEngineType::SKIA_GL_THREADED: + return "skiaglthreaded"; + case RenderEngine::RenderEngineType::SKIA_GL: + return "skiagl"; + case RenderEngine::RenderEngineType::GLES: + case RenderEngine::RenderEngineType::THREADED: + LOG_ALWAYS_FATAL("GLESRenderEngine is deprecated - why time it?"); + return "unused"; + } +} + +/** + * Passed (indirectly - see RunSkiaGL) to Benchmark::Apply to create a Benchmark + * which specifies which RenderEngineType it uses. + * + * This simplifies calling ->Arg(type)->Arg(type) and provides strings to make + * it obvious which version is being run. + * + * @param b The benchmark family + * @param type The type of RenderEngine to use. + */ +static void AddRenderEngineType(benchmark::internal::Benchmark* b, + RenderEngine::RenderEngineType type) { + b->Arg(static_cast(type)); + b->ArgName(RenderEngineTypeName(type)); +} + +/** + * Run a benchmark once using SKIA_GL. + */ +static void RunSkiaGL(benchmark::internal::Benchmark* b) { + AddRenderEngineType(b, RenderEngine::RenderEngineType::SKIA_GL); +} + +/////////////////////////////////////////////////////////////////////////////// +// Helpers for calling drawLayers +/////////////////////////////////////////////////////////////////////////////// + +std::pair getDisplaySize() { + // These will be retrieved from a ui::Size, which stores int32_t, but they will be passed + // to GraphicBuffer, which wants uint32_t. + static uint32_t width, height; + std::once_flag once; + std::call_once(once, []() { + auto surfaceComposerClient = SurfaceComposerClient::getDefault(); + auto displayToken = surfaceComposerClient->getInternalDisplayToken(); + ui::DisplayMode displayMode; + if (surfaceComposerClient->getActiveDisplayMode(displayToken, &displayMode) < 0) { + LOG_ALWAYS_FATAL("Failed to get active display mode!"); + } + auto w = displayMode.resolution.width; + auto h = displayMode.resolution.height; + LOG_ALWAYS_FATAL_IF(w <= 0 || h <= 0, "Invalid display size!"); + width = static_cast(w); + height = static_cast(h); + }); + return std::pair(width, height); +} + +// This value doesn't matter, as it's not read. TODO(b/199918329): Once we remove +// GLESRenderEngine we can remove this, too. +static constexpr const bool kUseFrameBufferCache = false; + +static std::unique_ptr createRenderEngine(RenderEngine::RenderEngineType type) { + auto args = RenderEngineCreationArgs::Builder() + .setPixelFormat(static_cast(ui::PixelFormat::RGBA_8888)) + .setImageCacheSize(1) + .setEnableProtectedContext(true) + .setPrecacheToneMapperShaderOnly(false) + .setSupportsBackgroundBlur(true) + .setContextPriority(RenderEngine::ContextPriority::REALTIME) + .setRenderEngineType(type) + .setUseColorManagerment(true) + .build(); + return RenderEngine::create(args); +} + +static std::shared_ptr allocateBuffer(RenderEngine& re, + uint32_t width, + uint32_t height, + uint64_t extraUsageFlags = 0, + std::string name = "output") { + return std::make_shared(new GraphicBuffer(width, height, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + GRALLOC_USAGE_HW_RENDER | + GRALLOC_USAGE_HW_TEXTURE | + extraUsageFlags, + std::move(name)), + re, + ExternalTexture::Usage::READABLE | + ExternalTexture::Usage::WRITEABLE); +} + +static std::shared_ptr copyBuffer(RenderEngine& re, + std::shared_ptr original, + uint64_t extraUsageFlags, std::string name) { + const uint32_t width = original->getBuffer()->getWidth(); + const uint32_t height = original->getBuffer()->getHeight(); + auto texture = allocateBuffer(re, width, height, extraUsageFlags, name); + + const Rect displayRect(0, 0, static_cast(width), static_cast(height)); + DisplaySettings display{ + .physicalDisplay = displayRect, + .clip = displayRect, + .maxLuminance = 500, + }; + + const FloatRect layerRect(0, 0, width, height); + LayerSettings layer{ + .geometry = + Geometry{ + .boundaries = layerRect, + }, + .source = + PixelSource{ + .buffer = + Buffer{ + .buffer = original, + }, + }, + .alpha = half(1.0f), + }; + auto layers = std::vector{layer}; + + auto [status, drawFence] = + re.drawLayers(display, layers, texture, kUseFrameBufferCache, base::unique_fd()).get(); + sp waitFence = new Fence(std::move(drawFence)); + waitFence->waitForever(LOG_TAG); + return texture; +} + +static void benchDrawLayers(RenderEngine& re, const std::vector& layers, + benchmark::State& benchState, const char* saveFileName) { + auto [width, height] = getDisplaySize(); + auto outputBuffer = allocateBuffer(re, width, height); + + const Rect displayRect(0, 0, static_cast(width), static_cast(height)); + DisplaySettings display{ + .physicalDisplay = displayRect, + .clip = displayRect, + .maxLuminance = 500, + }; + + base::unique_fd fence; + for (auto _ : benchState) { + auto [status, drawFence] = + re.drawLayers(display, layers, outputBuffer, kUseFrameBufferCache, std::move(fence)) + .get(); + fence = std::move(drawFence); + } + + if (renderenginebench::save() && saveFileName) { + sp waitFence = new Fence(std::move(fence)); + waitFence->waitForever(LOG_TAG); + + // Copy to a CPU-accessible buffer so we can encode it. + outputBuffer = copyBuffer(re, outputBuffer, GRALLOC_USAGE_SW_READ_OFTEN, "to_encode"); + + std::string outFile = base::GetExecutableDirectory(); + outFile.append("/"); + outFile.append(saveFileName); + outFile.append(".jpg"); + renderenginebench::encodeToJpeg(outFile.c_str(), outputBuffer->getBuffer()); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Benchmarks +/////////////////////////////////////////////////////////////////////////////// + +void BM_blur(benchmark::State& benchState) { + auto re = createRenderEngine(static_cast(benchState.range())); + + // Initially use cpu access so we can decode into it with AImageDecoder. + auto [width, height] = getDisplaySize(); + auto srcBuffer = allocateBuffer(*re, width, height, GRALLOC_USAGE_SW_WRITE_OFTEN, + "decoded_source"); + { + std::string srcImage = base::GetExecutableDirectory(); + srcImage.append("/resources/homescreen.png"); + renderenginebench::decode(srcImage.c_str(), srcBuffer->getBuffer()); + + // Now copy into GPU-only buffer for more realistic timing. + srcBuffer = copyBuffer(*re, srcBuffer, 0, "source"); + } + + const FloatRect layerRect(0, 0, width, height); + LayerSettings layer{ + .geometry = + Geometry{ + .boundaries = layerRect, + }, + .source = + PixelSource{ + .buffer = + Buffer{ + .buffer = srcBuffer, + }, + }, + .alpha = half(1.0f), + }; + LayerSettings blurLayer{ + .geometry = + Geometry{ + .boundaries = layerRect, + }, + .alpha = half(1.0f), + .skipContentDraw = true, + .backgroundBlurRadius = 60, + }; + + auto layers = std::vector{layer, blurLayer}; + benchDrawLayers(*re, layers, benchState, "blurred"); +} + +BENCHMARK(BM_blur)->Apply(RunSkiaGL); diff --git a/libs/renderengine/benchmark/RenderEngineBench.h b/libs/renderengine/benchmark/RenderEngineBench.h new file mode 100644 index 0000000000..1a25d77f00 --- /dev/null +++ b/libs/renderengine/benchmark/RenderEngineBench.h @@ -0,0 +1,65 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +using namespace android; + +/** + * Utilities for running benchmarks. + */ +namespace renderenginebench { +/** + * Parse RenderEngineBench-specific flags from the command line. + * + * --save Save the output buffer to a file to verify that it drew as + * expected. + */ +void parseFlags(int argc, char** argv); + +/** + * Parse flags for '--help' + */ +void parseFlagsForHelp(int argc, char** argv); + +/** + * Whether to save the drawing result to a file. + * + * True if --save was used on the command line. + */ +bool save(); + +/** + * Decode the image at 'path' into 'buffer'. + * + * Currently only used for debugging. The image will be scaled to fit the + * buffer if necessary. + * + * This assumes the buffer matches ANDROID_BITMAP_FORMAT_RGBA_8888. + * + * @param path Relative to the directory holding the executable. + */ +void decode(const char* path, const sp& buffer); + +/** + * Encode the buffer to a jpeg. + * + * This assumes the buffer matches ANDROID_BITMAP_FORMAT_RGBA_8888. + * + * @param path Relative to the directory holding the executable. + */ +void encodeToJpeg(const char* path, const sp& buffer); +} // namespace renderenginebench diff --git a/libs/renderengine/benchmark/main.cpp b/libs/renderengine/benchmark/main.cpp new file mode 100644 index 0000000000..7a62853c9f --- /dev/null +++ b/libs/renderengine/benchmark/main.cpp @@ -0,0 +1,32 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +int main(int argc, char** argv) { + // Initialize will exit if it sees '--help', so check for it and print info + // about our flags first. + renderenginebench::parseFlagsForHelp(argc, argv); + benchmark::Initialize(&argc, argv); + + // Calling this separately from parseFlagsForHelp prevents collisions with + // google-benchmark's flags, since Initialize will consume and remove flags + // it recognizes. + renderenginebench::parseFlags(argc, argv); + benchmark::RunSpecifiedBenchmarks(); + return 0; +} diff --git a/libs/renderengine/benchmark/resources/homescreen.png b/libs/renderengine/benchmark/resources/homescreen.png new file mode 100644 index 0000000000..997b72d7a3 Binary files /dev/null and b/libs/renderengine/benchmark/resources/homescreen.png differ -- cgit v1.2.3-59-g8ed1b From 82de19bc5532d68df8f497062882d8d594a4f8f2 Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Thu, 28 Oct 2021 16:34:42 +0200 Subject: Remove dead code around use_frame_rate_api There's no se polixy for ro.surface_flinger.use_frame_rate_api and it cannot be used by vendors, so the code is dead. Removing it cos there isn't a use case for disabling this API. Bug: 199911262 Test: n/a Change-Id: I45aabf5ced73d565a5d7adc73971f3615dde0abe --- services/surfaceflinger/Layer.cpp | 3 --- services/surfaceflinger/SurfaceFlinger.cpp | 3 --- services/surfaceflinger/SurfaceFlinger.h | 5 ----- services/surfaceflinger/SurfaceFlingerProperties.cpp | 8 -------- services/surfaceflinger/SurfaceFlingerProperties.h | 2 -- .../surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop | 10 ---------- .../sysprop/api/SurfaceFlingerProperties-current.txt | 4 ---- .../sysprop/api/SurfaceFlingerProperties-latest.txt | 4 ---- services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp | 2 -- .../surfaceflinger/tests/unittests/TestableSurfaceFlinger.h | 1 - 10 files changed, 42 deletions(-) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 388181c231..94781751fb 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1157,9 +1157,6 @@ void Layer::updateTreeHasFrameRateVote() { } bool Layer::setFrameRate(FrameRate frameRate) { - if (!mFlinger->useFrameRateApi) { - return false; - } if (mDrawingState.frameRate == frameRate) { return false; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8d7221c1dc..0626e7c810 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -339,7 +339,6 @@ Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB; ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888; Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB; ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888; -bool SurfaceFlinger::useFrameRateApi; bool SurfaceFlinger::enableSdrDimming; bool SurfaceFlinger::enableLatchUnsignaled; @@ -494,8 +493,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI android::hardware::details::setTrebleTestingOverride(true); } - useFrameRateApi = use_frame_rate_api(true); - mRefreshRateOverlaySpinner = property_get_bool("sf.debug.show_refresh_rate_overlay_spinner", 0); // Debug property overrides ro. property diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 276c7f6bfe..f67c8813a7 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -246,11 +246,6 @@ public: static ui::Dataspace wideColorGamutCompositionDataspace; static ui::PixelFormat wideColorGamutCompositionPixelFormat; - // Whether to use frame rate API when deciding about the refresh rate of the display. This - // variable is caches in SF, so that we can check it with each layer creation, and a void the - // overhead that is caused by reading from sysprop. - static bool useFrameRateApi; - static constexpr SkipInitializationTag SkipInitialization; // Whether or not SDR layers should be dimmed to the desired SDR white point instead of diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index a8117f7f57..16f6e31946 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -304,14 +304,6 @@ bool support_kernel_idle_timer(bool defaultValue) { return defaultValue; } -bool use_frame_rate_api(bool defaultValue) { - auto temp = SurfaceFlingerProperties::use_frame_rate_api(); - if (temp.has_value()) { - return *temp; - } - return defaultValue; -} - bool enable_sdr_dimming(bool defaultValue) { return SurfaceFlingerProperties::enable_sdr_dimming().value_or(defaultValue); } diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h index ed182608fb..8d0e4263b1 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -88,8 +88,6 @@ bool enable_protected_contents(bool defaultValue); bool support_kernel_idle_timer(bool defaultValue); -bool use_frame_rate_api(bool defaultValue); - int32_t display_update_imminent_timeout_ms(int32_t defaultValue); android::ui::DisplayPrimaries getDisplayNativePrimaries(); diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index 78f8a2f0ae..7702ea240b 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -414,16 +414,6 @@ prop { prop_name: "ro.surface_flinger.supports_background_blur" } -# Indicates whether Scheduler should use frame rate API when adjusting the -# display refresh rate. -prop { - api_name: "use_frame_rate_api" - type: Boolean - scope: Public - access: Readonly - prop_name: "ro.surface_flinger.use_frame_rate_api" -} - # Sets the timeout used to rate limit DISPLAY_UPDATE_IMMINENT Power HAL notifications. # SurfaceFlinger wakeups will trigger this boost whenever they are separated by more than this # duration (specified in milliseconds). A value of 0 disables the rate limit, and will result in diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt index 9c567d6afa..bf1e7e2908 100644 --- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt +++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt @@ -151,10 +151,6 @@ props { api_name: "use_context_priority" prop_name: "ro.surface_flinger.use_context_priority" } - prop { - api_name: "use_frame_rate_api" - prop_name: "ro.surface_flinger.use_frame_rate_api" - } prop { api_name: "use_smart_90_for_video" prop_name: "ro.surface_flinger.use_smart_90_for_video" diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt index ba60a7defb..640b9fb163 100644 --- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt +++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt @@ -135,10 +135,6 @@ props { api_name: "use_context_priority" prop_name: "ro.surface_flinger.use_context_priority" } - prop { - api_name: "use_frame_rate_api" - prop_name: "ro.surface_flinger.use_frame_rate_api" - } prop { api_name: "use_smart_90_for_video" prop_name: "ro.surface_flinger.use_smart_90_for_video" diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index 3b409658d7..d0211780ab 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -122,8 +122,6 @@ SetFrameRateTest::SetFrameRateTest() { ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - mFlinger.mutableUseFrameRateApi() = true; - setupScheduler(); mFlinger.setupComposer(std::make_unique()); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index c23fcc7d58..2c48779b9d 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -445,7 +445,6 @@ public: auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; } auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; } auto& mutablePrimaryHwcDisplayId() { return getHwComposer().mPrimaryHwcDisplayId; } - auto& mutableUseFrameRateApi() { return mFlinger->useFrameRateApi; } auto& mutableActiveDisplayToken() { return mFlinger->mActiveDisplayToken; } auto fromHandle(const sp& handle) { -- cgit v1.2.3-59-g8ed1b From caaa47d60b83670206dcd3c34382719b1f247ab5 Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Fri, 29 Oct 2021 18:03:52 +0000 Subject: Revert "Send multiple scheduler frame timelines." This reverts commit 6b1807002ebd198f51cdb70c3fee79645bd25fe8. Reason for revert: b/204492891 Change-Id: I292c11a0c54c57d97d112d9cec16b27acaa7b6a6 --- libs/gui/DisplayEventDispatcher.cpp | 16 ------- libs/gui/include/gui/DisplayEventDispatcher.h | 24 ---------- libs/gui/include/gui/DisplayEventReceiver.h | 9 ---- libs/nativedisplay/AChoreographer.cpp | 34 ++++++++++----- services/surfaceflinger/Scheduler/EventThread.cpp | 45 ++++--------------- services/surfaceflinger/Scheduler/EventThread.h | 4 -- .../tests/unittests/EventThreadTest.cpp | 51 +--------------------- 7 files changed, 33 insertions(+), 150 deletions(-) diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp index c986b82fd8..6f1a7aed9c 100644 --- a/libs/gui/DisplayEventDispatcher.cpp +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -130,19 +130,6 @@ int DisplayEventDispatcher::handleEvent(int, int events, void*) { return 1; // keep the callback } -void DisplayEventDispatcher::populateFrameTimelines(const DisplayEventReceiver::Event& event, - VsyncEventData* outVsyncEventData) const { - for (size_t i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) { - DisplayEventReceiver::Event::VSync::FrameTimeline receiverTimeline = - event.vsync.frameTimelines[i]; - outVsyncEventData->frameTimelines[i] = {.id = receiverTimeline.vsyncId, - .deadlineTimestamp = - receiverTimeline.deadlineTimestamp, - .expectedPresentTime = - receiverTimeline.expectedVSyncTimestamp}; - } -} - bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, uint32_t* outCount, @@ -167,9 +154,6 @@ bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp; outVsyncEventData->frameInterval = ev.vsync.frameInterval; outVsyncEventData->expectedPresentTime = ev.vsync.expectedVSyncTimestamp; - outVsyncEventData->preferredFrameTimelineIndex = - ev.vsync.preferredFrameTimelineIndex; - populateFrameTimelines(ev, outVsyncEventData); break; case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected); diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h index 92c89b8bde..f3bd139e8c 100644 --- a/libs/gui/include/gui/DisplayEventDispatcher.h +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -17,7 +17,6 @@ #include #include #include -#include namespace android { using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; @@ -37,26 +36,6 @@ struct VsyncEventData { // The anticipated Vsync present time. int64_t expectedPresentTime = 0; - - struct FrameTimeline { - // The Vsync Id corresponsing to this vsync event. This will be used to - // populate ISurfaceComposer::setFrameTimelineVsync and - // SurfaceComposerClient::setFrameTimelineVsync - int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID; - - // The deadline in CLOCK_MONOTONIC that the app needs to complete its - // frame by (both on the CPU and the GPU) - int64_t deadlineTimestamp = std::numeric_limits::max(); - - // The anticipated Vsync present time. - int64_t expectedPresentTime = 0; - }; - - // Sorted possible frame timelines. - std::array frameTimelines; - - // Index into the frameTimelines that represents the platform's preferred frame timeline. - size_t preferredFrameTimelineIndex = std::numeric_limits::max(); }; class DisplayEventDispatcher : public LooperCallback { @@ -98,8 +77,5 @@ private: bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, uint32_t* outCount, VsyncEventData* outVsyncEventData); - - void populateFrameTimelines(const DisplayEventReceiver::Event& event, - VsyncEventData* outVsyncEventData) const; }; } // namespace android diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index ca368433b1..0dffbde88a 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -49,9 +49,6 @@ static inline constexpr uint32_t fourcc(char c1, char c2, char c3, char c4) { // ---------------------------------------------------------------------------- class DisplayEventReceiver { public: - // Max amount of frame timelines is arbitrarily set to be reasonable. - static constexpr int64_t kFrameTimelinesLength = 7; - enum { DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'), DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'), @@ -80,12 +77,6 @@ public: nsecs_t deadlineTimestamp __attribute__((aligned(8))); nsecs_t frameInterval __attribute__((aligned(8))); int64_t vsyncId; - size_t preferredFrameTimelineIndex __attribute__((aligned(8))); - struct FrameTimeline { - nsecs_t expectedVSyncTimestamp __attribute__((aligned(8))); - nsecs_t deadlineTimestamp __attribute__((aligned(8))); - int64_t vsyncId; - } frameTimelines[kFrameTimelinesLength]; }; struct Hotplug { diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index fc9680babb..79d9b9313c 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -100,10 +100,17 @@ class Choreographer; * Implementation of AChoreographerFrameCallbackData. */ struct ChoreographerFrameCallbackDataImpl { + struct FrameTimeline { + int64_t vsyncId{0}; + int64_t expectedPresentTimeNanos{0}; + int64_t deadlineNanos{0}; + }; + int64_t frameTimeNanos{0}; - std::array - frameTimelines; + size_t frameTimelinesLength; + + std::vector frameTimelines; size_t preferredFrameTimelineIndex; @@ -449,9 +456,14 @@ bool Choreographer::inCallback() const { } ChoreographerFrameCallbackDataImpl Choreographer::createFrameCallbackData(nsecs_t timestamp) const { + std::vector frameTimelines; + frameTimelines.push_back({.vsyncId = mLastVsyncEventData.id, + .expectedPresentTimeNanos = mLastVsyncEventData.expectedPresentTime, + .deadlineNanos = mLastVsyncEventData.deadlineTimestamp}); return {.frameTimeNanos = timestamp, - .preferredFrameTimelineIndex = mLastVsyncEventData.preferredFrameTimelineIndex, - .frameTimelines = mLastVsyncEventData.frameTimelines, + .frameTimelinesLength = 1, + .preferredFrameTimelineIndex = 0, + .frameTimelines = frameTimelines, .choreographer = this}; } @@ -634,7 +646,7 @@ size_t AChoreographerFrameCallbackData_getFrameTimelinesLength( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - return frameCallbackData->frameTimelines.size(); + return frameCallbackData->frameTimelinesLength; } size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex( const AChoreographerFrameCallbackData* data) { @@ -650,8 +662,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineVsyncId( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); - return frameCallbackData->frameTimelines[index].id; + LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds"); + return frameCallbackData->frameTimelines[index].vsyncId; } int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime( const AChoreographerFrameCallbackData* data, size_t index) { @@ -659,8 +671,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); - return frameCallbackData->frameTimelines[index].expectedPresentTime; + LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds"); + return frameCallbackData->frameTimelines[index].expectedPresentTimeNanos; } int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline( const AChoreographerFrameCallbackData* data, size_t index) { @@ -668,8 +680,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); - return frameCallbackData->frameTimelines[index].deadlineTimestamp; + LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds"); + return frameCallbackData->frameTimelines[index].deadlineNanos; } AChoreographer* AChoreographer_create() { diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index e07eae79c8..2bdcaf6ad0 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -355,7 +355,14 @@ void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp std::lock_guard lock(mMutex); LOG_FATAL_IF(!mVSyncState); - const int64_t vsyncId = generateToken(timestamp, deadlineTimestamp, expectedVSyncTimestamp); + const int64_t vsyncId = [&] { + if (mTokenManager != nullptr) { + return mTokenManager->generateTokenForPredictions( + {timestamp, deadlineTimestamp, expectedVSyncTimestamp}); + } + return FrameTimelineInfo::INVALID_VSYNC_ID; + }(); + mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count, expectedVSyncTimestamp, deadlineTimestamp, vsyncId)); mCondition.notify_all(); @@ -560,48 +567,12 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, } } -int64_t EventThread::generateToken(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, - nsecs_t deadlineTimestamp) const { - if (mTokenManager != nullptr) { - return mTokenManager->generateTokenForPredictions( - {timestamp, deadlineTimestamp, expectedVSyncTimestamp}); - } - return FrameTimelineInfo::INVALID_VSYNC_ID; -} - -void EventThread::generateFrameTimeline(DisplayEventReceiver::Event& event) const { - // Add 1 to ensure the preferredFrameTimelineIndex entry (when multiplier == 0) is included. - for (int multiplier = -DisplayEventReceiver::kFrameTimelinesLength + 1, currentIndex = 0; - currentIndex < DisplayEventReceiver::kFrameTimelinesLength; multiplier++) { - nsecs_t deadline = event.vsync.deadlineTimestamp + multiplier * event.vsync.frameInterval; - // Valid possible frame timelines must have future values. - if (deadline > event.header.timestamp) { - if (multiplier == 0) { - event.vsync.preferredFrameTimelineIndex = currentIndex; - event.vsync.frameTimelines[currentIndex] = - {.vsyncId = event.vsync.vsyncId, - .deadlineTimestamp = event.vsync.deadlineTimestamp, - .expectedVSyncTimestamp = event.vsync.expectedVSyncTimestamp}; - } else { - nsecs_t expectedVSync = - event.vsync.expectedVSyncTimestamp + multiplier * event.vsync.frameInterval; - event.vsync.frameTimelines[currentIndex] = - {.vsyncId = generateToken(event.header.timestamp, expectedVSync, deadline), - .deadlineTimestamp = deadline, - .expectedVSyncTimestamp = expectedVSync}; - } - currentIndex++; - } - } -} - void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event, const DisplayEventConsumers& consumers) { for (const auto& consumer : consumers) { DisplayEventReceiver::Event copy = event; if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { copy.vsync.frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid); - generateFrameTimeline(copy); } switch (consumer->postEvent(copy)) { case NO_ERROR: diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 73ae5dc9e3..9265a25b86 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -204,10 +204,6 @@ private: void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, nsecs_t deadlineTimestamp) override; - int64_t generateToken(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, - nsecs_t deadlineTimestamp) const; - void generateFrameTimeline(DisplayEventReceiver::Event& event) const; - const std::unique_ptr mVSyncSource GUARDED_BY(mMutex); frametimeline::TokenManager* const mTokenManager; diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index cb690aa0e4..28d0222829 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -28,7 +28,6 @@ #include "AsyncCallRecorder.h" #include "DisplayHardware/DisplayMode.h" -#include "FrameTimeline.h" #include "Scheduler/EventThread.h" using namespace std::chrono_literals; @@ -97,8 +96,6 @@ protected: ConnectionEventRecorder& connectionEventRecorder, nsecs_t expectedTimestamp, unsigned expectedCount); void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount); - void expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp, - nsecs_t preferredDeadline); void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, bool expectedConnected); void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, @@ -123,7 +120,6 @@ protected: std::unique_ptr mThread; sp mConnection; sp mThrottledConnection; - std::unique_ptr mTokenManager; static constexpr uid_t mConnectionUid = 443; static constexpr uid_t mThrottledConnectionUid = 177; @@ -177,8 +173,8 @@ void EventThreadTest::createThread(std::unique_ptr source) { return VSYNC_PERIOD.count(); }; - mTokenManager = std::make_unique(); - mThread = std::make_unique(std::move(source), mTokenManager.get(), + mThread = std::make_unique(std::move(source), + /*tokenManager=*/nullptr, mInterceptVSyncCallRecorder.getInvocable(), throttleVsync, getVsyncPeriod); @@ -251,36 +247,6 @@ void EventThreadTest::expectVsyncEventReceivedByConnection(nsecs_t expectedTimes expectedCount); } -void EventThreadTest::expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp, - nsecs_t preferredDeadline) { - auto args = mConnectionEventCallRecorder.waitForCall(); - ASSERT_TRUE(args.has_value()) << " did not receive an event for timestamp " - << expectedTimestamp; - const auto& event = std::get<0>(args.value()); - for (int i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) { - if (i > 0) { - EXPECT_GT(event.vsync.frameTimelines[i].deadlineTimestamp, - event.vsync.frameTimelines[i - 1].deadlineTimestamp) - << "Deadline timestamp out of order for frame timeline " << i; - EXPECT_GT(event.vsync.frameTimelines[i].expectedVSyncTimestamp, - event.vsync.frameTimelines[i - 1].expectedVSyncTimestamp) - << "Expected vsync timestamp out of order for frame timeline " << i; - } - if (event.vsync.frameTimelines[i].deadlineTimestamp == preferredDeadline) { - EXPECT_EQ(i, event.vsync.preferredFrameTimelineIndex) - << "Preferred frame timeline index should be " << i; - // For the platform-preferred frame timeline, the vsync ID is 0 because the first frame - // timeline is made before the rest. - EXPECT_EQ(0, event.vsync.frameTimelines[i].vsyncId) - << "Vsync ID incorrect for frame timeline " << i; - } else { - // Vsync ID 0 is used for the preferred frame timeline. - EXPECT_EQ(i + 1, event.vsync.frameTimelines[i].vsyncId) - << "Vsync ID incorrect for frame timeline " << i; - } - } -} - void EventThreadTest::expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, bool expectedConnected) { auto args = mConnectionEventCallRecorder.waitForCall(); @@ -378,19 +344,6 @@ TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) { expectVSyncSetEnabledCallReceived(false); } -TEST_F(EventThreadTest, requestNextVsyncEventFrameTimelinesCorrect) { - // Signal that we want the next vsync event to be posted to the connection - mThread->requestNextVsync(mConnection); - - expectVSyncSetEnabledCallReceived(true); - - // Use the received callback to signal a vsync event. - // The interceptor should receive the event, as well as the connection. - mCallback->onVSyncEvent(123, 456, 789); - expectInterceptCallReceived(123); - expectVsyncEventFrameTimelinesCorrect(123, 789); -} - TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) { // Create a first connection, register it, and request a vsync rate of zero. ConnectionEventRecorder firstConnectionEventRecorder{0}; -- cgit v1.2.3-59-g8ed1b From a64c272fa2fac03883ec858fcd5ceabcc6b0b1d1 Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Wed, 1 Sep 2021 16:39:16 +0100 Subject: Give access to the native InputQueue to all native applications. Bug: 116830907 Test: atest android.view.cts.InputQueueTest#testNativeInputQueue Change-Id: Ia92de418fe3407d0fa074f9fcb45d8844acbdf59 --- include/android/input.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/android/input.h b/include/android/input.h index 6d2c1b3015..27587ce483 100644 --- a/include/android/input.h +++ b/include/android/input.h @@ -1385,6 +1385,14 @@ int32_t AInputQueue_preDispatchEvent(AInputQueue* queue, AInputEvent* event); */ void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled); +/** + * Supplies the AInputQueue* object associated with the supplied Java InputQueue + * object. + * + * Available since API level 33. + */ +AInputQueue* AInputQueue_fromJava(jobject inputQueue) __INTRODUCED_IN(33); + #ifdef __cplusplus } #endif -- cgit v1.2.3-59-g8ed1b From 768bfa07e598608f135140f1001bf09c7de35b1e Mon Sep 17 00:00:00 2001 From: chaviw Date: Mon, 1 Nov 2021 09:50:57 -0500 Subject: Change log to match with function it's coming from Added the function name in the error log when SurfaceControl can't be found in the callbacks. Test: Log Bug: 200285149 Change-Id: I6c721a699c25c8659f5aa5e703de134c8c0a31b7 --- libs/gui/BLASTBufferQueue.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 1ae90f34f5..9080822f92 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -296,7 +296,7 @@ void BLASTBufferQueue::transactionCommittedCallback(nsecs_t /*latchTime*/, flushShadowQueue(); } } else { - BQA_LOGE("Failed to find matching SurfaceControl in transaction callback"); + BQA_LOGE("Failed to find matching SurfaceControl in transactionCommittedCallback"); } } else { BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was " @@ -346,7 +346,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp Date: Wed, 27 Oct 2021 11:11:24 -0500 Subject: Allow offscreen mirrored layers to be captured. If an offscreen layer is valid and has content, we should be able to take a screen capture of it. If we're mirroring content, but it's not on screen, we need to ensure updateMirrorInfo is called to get the updated hierarchy. This will allow the mirror content to get properly screenshot Test: screencapture offscreen Test: MirrorLayerTest Test: ScreenCaptureTest Change-Id: I31f806eb616e2d6f800da6328c9878a3e47d6a14 Bug: 188222480 --- services/surfaceflinger/LayerRenderArea.cpp | 14 ++++++ services/surfaceflinger/SurfaceFlinger.cpp | 46 +++++++++--------- services/surfaceflinger/SurfaceFlinger.h | 1 + .../surfaceflinger/tests/InvalidHandles_test.cpp | 11 ----- services/surfaceflinger/tests/MirrorLayer_test.cpp | 55 ++++++++++++++++++++++ .../surfaceflinger/tests/ScreenCapture_test.cpp | 42 ++++++++++++----- .../surfaceflinger/tests/utils/ScreenshotUtils.h | 5 ++ 7 files changed, 128 insertions(+), 46 deletions(-) diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp index e84508febc..11fe6d0755 100644 --- a/services/surfaceflinger/LayerRenderArea.cpp +++ b/services/surfaceflinger/LayerRenderArea.cpp @@ -94,8 +94,22 @@ void LayerRenderArea::render(std::function drawLayers) { // no need to check rotation because there is none mNeedsFiltering = sourceCrop.width() != getReqWidth() || sourceCrop.height() != getReqHeight(); + // If layer is offscreen, update mirroring info if it exists + if (mLayer->isRemovedFromCurrentState()) { + mLayer->traverse(LayerVector::StateSet::Drawing, + [&](Layer* layer) { layer->updateMirrorInfo(); }); + mLayer->traverse(LayerVector::StateSet::Drawing, + [&](Layer* layer) { layer->updateCloneBufferInfo(); }); + } + if (!mChildrenOnly) { mTransform = mLayer->getTransform().inverse(); + // If the layer is offscreen, compute bounds since we don't compute bounds for offscreen + // layers in a regular cycles. + if (mLayer->isRemovedFromCurrentState()) { + FloatRect maxBounds = mFlinger.getMaxDisplayBounds(); + mLayer->computeBounds(maxBounds, ui::Transform(), 0.f /* shadowRadius */); + } drawLayers(); } else { uint32_t w = static_cast(getWidth()); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8d7221c1dc..d4e28ce071 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2428,7 +2428,7 @@ void SurfaceFlinger::postComposition() { } } -void SurfaceFlinger::computeLayerBounds() { +FloatRect SurfaceFlinger::getMaxDisplayBounds() { // Find the largest width and height among all the displays. int32_t maxDisplayWidth = 0; int32_t maxDisplayHeight = 0; @@ -2446,8 +2446,13 @@ void SurfaceFlinger::computeLayerBounds() { // Ignore display bounds for now since they will be computed later. Use a large Rect bound // to ensure it's bigger than an actual display will be. - FloatRect maxBounds(-maxDisplayWidth * 10, -maxDisplayHeight * 10, maxDisplayWidth * 10, - maxDisplayHeight * 10); + FloatRect maxBounds = FloatRect(-maxDisplayWidth * 10, -maxDisplayHeight * 10, + maxDisplayWidth * 10, maxDisplayHeight * 10); + return maxBounds; +} + +void SurfaceFlinger::computeLayerBounds() { + FloatRect maxBounds = getMaxDisplayBounds(); for (const auto& layer : mDrawingState.layersSortedByZ) { layer->computeBounds(maxBounds, ui::Transform(), 0.f /* shadowRadius */); } @@ -5978,9 +5983,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, sp parent; Rect crop(args.sourceCrop); std::unordered_set, ISurfaceComposer::SpHash> excludeLayers; - Rect layerStackSpaceRect; ui::Dataspace dataspace; - bool captureSecureLayers; // Call this before holding mStateLock to avoid any deadlocking. bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission(); @@ -5989,7 +5992,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, Mutex::Autolock lock(mStateLock); parent = fromHandle(args.layerHandle).promote(); - if (parent == nullptr || parent->isRemovedFromCurrentState()) { + if (parent == nullptr) { ALOGE("captureLayers called with an invalid or removed parent"); return NAME_NOT_FOUND; } @@ -6028,43 +6031,38 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, } } - const auto display = - findDisplay([layerStack = parent->getLayerStack()](const auto& display) { - return display.getLayerStack() == layerStack; - }); - - if (!display) { - return NAME_NOT_FOUND; - } - - layerStackSpaceRect = display->getLayerStackSpaceRect(); - // The dataspace is depended on the color mode of display, that could use non-native mode // (ex. displayP3) to enhance the content, but some cases are checking native RGB in bytes, // and failed if display is not in native mode. This provide a way to force using native // colors when capture. dataspace = args.dataspace; if (dataspace == ui::Dataspace::UNKNOWN) { + auto display = findDisplay([layerStack = parent->getLayerStack()](const auto& display) { + return display.getLayerStack() == layerStack; + }); + if (!display) { + // If the layer is not on a display, use the dataspace for the default display. + display = getDefaultDisplayDeviceLocked(); + } + const ui::ColorMode colorMode = display->getCompositionDisplay()->getState().colorMode; dataspace = pickDataspaceFromColorMode(colorMode); } - captureSecureLayers = args.captureSecureLayers && display->isSecure(); } // mStateLock // really small crop or frameScale - if (reqSize.width <= 0) { - reqSize.width = 1; - } - if (reqSize.height <= 0) { - reqSize.height = 1; + if (reqSize.width <= 0 || reqSize.height <= 0) { + ALOGW("Failed to captureLayes: crop or scale too small"); + return BAD_VALUE; } + Rect layerStackSpaceRect(0, 0, reqSize.width, reqSize.height); bool childrenOnly = args.childrenOnly; RenderAreaFuture renderAreaFuture = ftl::defer([=]() -> std::unique_ptr { return std::make_unique(*this, parent, crop, reqSize, dataspace, childrenOnly, layerStackSpaceRect, - captureSecureLayers); + args.captureSecureLayers); }); auto traverseLayers = [parent, args, excludeLayers](const LayerVector::Visitor& visitor) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 276c7f6bfe..806b5b5cdf 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -326,6 +326,7 @@ public: // Disables expensive rendering for all displays // This is scheduled on the main thread void disableExpensiveRendering(); + FloatRect getMaxDisplayBounds(); protected: // We're reference counted, never destroy SurfaceFlinger directly diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp index 9cf7c0909b..d192a2d83d 100644 --- a/services/surfaceflinger/tests/InvalidHandles_test.cpp +++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp @@ -52,17 +52,6 @@ protected: } }; -TEST_F(InvalidHandleTest, createSurfaceInvalidParentHandle) { - // The createSurface is scheduled now, we could still get a created surface from createSurface. - // Should verify if it actually added into current state by checking the screenshot. - auto notSc = mScc->createSurface(String8("lolcats"), 19, 47, PIXEL_FORMAT_RGBA_8888, 0, - mNotSc->getHandle()); - LayerCaptureArgs args; - args.layerHandle = notSc->getHandle(); - ScreenCaptureResults captureResults; - ASSERT_EQ(NAME_NOT_FOUND, ScreenCapture::captureLayers(args, captureResults)); -} - TEST_F(InvalidHandleTest, captureLayersInvalidHandle) { LayerCaptureArgs args; args.layerHandle = mNotSc->getHandle(); diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp index 3ec6da9ff4..a921aa810e 100644 --- a/services/surfaceflinger/tests/MirrorLayer_test.cpp +++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp @@ -273,6 +273,61 @@ TEST_F(MirrorLayerTest, InitialMirrorState) { } } +// Test that a mirror layer can be screenshot when offscreen +TEST_F(MirrorLayerTest, OffscreenMirrorScreenshot) { + const auto display = SurfaceComposerClient::getInternalDisplayToken(); + ui::DisplayMode mode; + SurfaceComposerClient::getActiveDisplayMode(display, &mode); + const ui::Size& size = mode.resolution; + + sp grandchild = + createLayer("Grandchild layer", 50, 50, ISurfaceComposerClient::eFXSurfaceBufferState, + mChildLayer.get()); + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(grandchild, Color::BLUE, 50, 50)); + Rect childBounds = Rect(50, 50, 450, 450); + + asTransaction([&](Transaction& t) { + t.setCrop(grandchild, Rect(0, 0, 50, 50)).show(grandchild); + t.setFlags(grandchild, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque); + }); + + sp mirrorLayer = nullptr; + { + // Run as system to get the ACCESS_SURFACE_FLINGER permission when mirroring + UIDFaker f(AID_SYSTEM); + // Mirror mChildLayer + mirrorLayer = mClient->mirrorSurface(mChildLayer.get()); + ASSERT_NE(mirrorLayer, nullptr); + } + + // Show the mirror layer, but don't reparent to a layer on screen. + Transaction().show(mirrorLayer).apply(); + + { + SCOPED_TRACE("Offscreen Mirror"); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, size.getWidth(), 50), Color::RED); + shot->expectColor(Rect(0, 0, 50, size.getHeight()), Color::RED); + shot->expectColor(Rect(450, 0, size.getWidth(), size.getHeight()), Color::RED); + shot->expectColor(Rect(0, 450, size.getWidth(), size.getHeight()), Color::RED); + shot->expectColor(Rect(100, 100, 450, 450), Color::GREEN); + shot->expectColor(Rect(50, 50, 100, 100), Color::BLUE); + } + + { + SCOPED_TRACE("Capture Mirror"); + // Capture just the mirror layer and child. + LayerCaptureArgs captureArgs; + captureArgs.layerHandle = mirrorLayer->getHandle(); + captureArgs.sourceCrop = childBounds; + std::unique_ptr shot; + ScreenCapture::captureLayers(&shot, captureArgs); + shot->expectSize(childBounds.width(), childBounds.height()); + shot->expectColor(Rect(0, 0, 50, 50), Color::BLUE); + shot->expectColor(Rect(50, 50, 400, 400), Color::GREEN); + } +} + } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp index 95301b3a37..f9b31853fc 100644 --- a/services/surfaceflinger/tests/ScreenCapture_test.cpp +++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp @@ -37,6 +37,8 @@ protected: ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode)); const ui::Size& resolution = mode.resolution; + mDisplaySize = resolution; + // Background surface mBGSurfaceControl = createLayer(String8("BG Test Surface"), resolution.getWidth(), resolution.getHeight(), 0); @@ -72,6 +74,7 @@ protected: sp mBGSurfaceControl; sp mFGSurfaceControl; std::unique_ptr mCapture; + ui::Size mDisplaySize; }; TEST_F(ScreenCaptureTest, SetFlagsSecureEUidSystem) { @@ -515,18 +518,8 @@ TEST_F(ScreenCaptureTest, CaptureSize) { } TEST_F(ScreenCaptureTest, CaptureInvalidLayer) { - sp redLayer = createLayer(String8("Red surface"), 60, 60, - ISurfaceComposerClient::eFXSurfaceBufferState); - - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60)); - - auto redLayerHandle = redLayer->getHandle(); - Transaction().reparent(redLayer, nullptr).apply(); - redLayer.clear(); - SurfaceComposerClient::Transaction().apply(true); - LayerCaptureArgs args; - args.layerHandle = redLayerHandle; + args.layerHandle = new BBinder(); ScreenCaptureResults captureResults; // Layer was deleted so captureLayers should fail with NAME_NOT_FOUND @@ -840,6 +833,33 @@ TEST_F(ScreenCaptureTest, CaptureWithGrayscale) { Color{expectedColor, expectedColor, expectedColor, 255}, tolerance); } +TEST_F(ScreenCaptureTest, CaptureOffscreen) { + sp layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32, + ISurfaceComposerClient::eFXSurfaceBufferState, + mBGSurfaceControl.get())); + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); + + Transaction().show(layer).hide(mFGSurfaceControl).reparent(layer, nullptr).apply(); + + DisplayCaptureArgs displayCaptureArgs; + displayCaptureArgs.displayToken = mDisplay; + + { + // Validate that the red layer is not on screen + ScreenCapture::captureDisplay(&mCapture, displayCaptureArgs); + mCapture->expectColor(Rect(0, 0, mDisplaySize.width, mDisplaySize.height), + {63, 63, 195, 255}); + } + + LayerCaptureArgs captureArgs; + captureArgs.layerHandle = layer->getHandle(); + + ScreenCapture::captureLayers(&mCapture, captureArgs); + mCapture->expectSize(32, 32); + mCapture->expectColor(Rect(0, 0, 32, 32), Color::RED); +} + // In the following tests we verify successful skipping of a parent layer, // so we use the same verification logic and only change how we mutate // the parent layer to verify that various properties are ignored. diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h index ddaa5a166e..cae76849bf 100644 --- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h +++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h @@ -175,6 +175,11 @@ public: void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); } + void expectSize(uint32_t width, uint32_t height) { + EXPECT_EQ(width, mOutBuffer->getWidth()); + EXPECT_EQ(height, mOutBuffer->getHeight()); + } + explicit ScreenCapture(const sp& outBuffer) : mOutBuffer(outBuffer) { if (mOutBuffer) { mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast(&mPixels)); -- cgit v1.2.3-59-g8ed1b From fa39ee7c602bcd91f9889d931ff80377988008b7 Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Mon, 1 Nov 2021 14:04:27 +0100 Subject: Remove frame rate flexibility token Remove the frame rate flexiblity token which can be replaced with DisplayManager.setRefreshRateSwitchingType( DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS); DisplayManager.setShouldAlwaysRespectAppRequestedMode(true); Bug: 175371491 Test: m Test: manually test that backdoor still works adb shell dumpsys SurfaceFlinger | grep -A 15 "DesiredDisplayModeSpecs" verify no override adb shell service call SurfaceFlinger 1036 i32 1 adb shell dumpsys SurfaceFlinger | grep -A 15 "DesiredDisplayModeSpecs" verify there is override adb shell service call SurfaceFlinger 1036 i32 0 adb shell dumpsys SurfaceFlinger | grep -A 15 "DesiredDisplayModeSpecs" verify no override verify idempotence: adb shell service call SurfaceFlinger 1036 i32 0 adb shell service call SurfaceFlinger 1036 i32 0 adb shell service call SurfaceFlinger 1036 i32 1 adb shell service call SurfaceFlinger 1036 i32 1 Change-Id: I848f849037da38d245e940bc9c85727129463a81 --- libs/gui/ISurfaceComposer.cpp | 45 ----------- libs/gui/include/gui/ISurfaceComposer.h | 9 +-- libs/gui/tests/Surface_test.cpp | 4 - services/surfaceflinger/SurfaceFlinger.cpp | 124 ++++++++--------------------- services/surfaceflinger/SurfaceFlinger.h | 7 -- 5 files changed, 35 insertions(+), 154 deletions(-) diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 3c8289fe2a..02950995af 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -1150,41 +1150,6 @@ public: return reply.readInt32(); } - status_t acquireFrameRateFlexibilityToken(sp* outToken) override { - if (!outToken) return BAD_VALUE; - - Parcel data, reply; - status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (err != NO_ERROR) { - ALOGE("acquireFrameRateFlexibilityToken: failed writing interface token: %s (%d)", - strerror(-err), -err); - return err; - } - - err = remote()->transact(BnSurfaceComposer::ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN, data, - &reply); - if (err != NO_ERROR) { - ALOGE("acquireFrameRateFlexibilityToken: failed to transact: %s (%d)", strerror(-err), - err); - return err; - } - - err = reply.readInt32(); - if (err != NO_ERROR) { - ALOGE("acquireFrameRateFlexibilityToken: call failed: %s (%d)", strerror(-err), err); - return err; - } - - err = reply.readStrongBinder(outToken); - if (err != NO_ERROR) { - ALOGE("acquireFrameRateFlexibilityToken: failed reading binder token: %s (%d)", - strerror(-err), err); - return err; - } - - return NO_ERROR; - } - status_t setFrameTimelineInfo(const sp& surface, const FrameTimelineInfo& frameTimelineInfo) override { Parcel data, reply; @@ -2073,16 +2038,6 @@ status_t BnSurfaceComposer::onTransact( reply->writeInt32(result); return NO_ERROR; } - case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp token; - status_t result = acquireFrameRateFlexibilityToken(&token); - reply->writeInt32(result); - if (result == NO_ERROR) { - reply->writeStrongBinder(token); - } - return NO_ERROR; - } case SET_FRAME_TIMELINE_INFO: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp binder; diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 408497dd36..e0183adbe6 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -511,14 +511,6 @@ public: virtual status_t setFrameRate(const sp& surface, float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) = 0; - /* - * Acquire a frame rate flexibility token from SurfaceFlinger. While this token is acquired, - * surface flinger will freely switch between frame rates in any way it sees fit, regardless of - * the current restrictions applied by DisplayManager. This is useful to get consistent behavior - * for tests. Release the token by releasing the returned IBinder reference. - */ - virtual status_t acquireFrameRateFlexibilityToken(sp* outToken) = 0; - /* * Sets the frame timeline vsync info received from choreographer that corresponds to next * buffer submitted on that surface. @@ -616,6 +608,7 @@ public: GET_GAME_CONTENT_TYPE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. SET_GAME_CONTENT_TYPE, SET_FRAME_RATE, + // Deprecated. Use DisplayManager.setShouldAlwaysRespectAppRequestedMode(true); ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN, SET_FRAME_TIMELINE_INFO, ADD_TRANSACTION_TRACE_LISTENER, diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index a9f4d09838..b2baea6aba 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -885,10 +885,6 @@ public: return NO_ERROR; } - status_t acquireFrameRateFlexibilityToken(sp* /*outToken*/) override { - return NO_ERROR; - } - status_t setFrameTimelineInfo(const sp& /*surface*/, const FrameTimelineInfo& /*frameTimelineInfo*/) override { return NO_ERROR; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8d7221c1dc..6bd5b01660 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -263,14 +263,6 @@ bool validateCompositionDataspace(Dataspace dataspace) { return dataspace == Dataspace::V0_SRGB || dataspace == Dataspace::DISPLAY_P3; } -class FrameRateFlexibilityToken : public BBinder { -public: - FrameRateFlexibilityToken(std::function callback) : mCallback(callback) {} - virtual ~FrameRateFlexibilityToken() { mCallback(); } - -private: - std::function mCallback; -}; enum Permission { ACCESS_SURFACE_FLINGER = 0x1, @@ -5154,11 +5146,9 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case SET_GLOBAL_SHADOW_SETTINGS: case GET_PRIMARY_PHYSICAL_DISPLAY_ID: case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: { - // ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN and OVERRIDE_HDR_TYPES are used by CTS tests, - // which acquire the necessary permission dynamically. Don't use the permission cache - // for this check. - bool usePermissionCache = - code != ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN && code != OVERRIDE_HDR_TYPES; + // OVERRIDE_HDR_TYPES is used by CTS tests, which acquire the necessary + // permission dynamically. Don't use the permission cache for this check. + bool usePermissionCache = code != OVERRIDE_HDR_TYPES; if (!callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) { IPCThreadState* ipc = IPCThreadState::self(); ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", @@ -5610,17 +5600,39 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r mDebugDisplayModeSetByBackdoor = result == NO_ERROR; return result; } + // Turn on/off frame rate flexibility mode. When turned on it overrides the display + // manager frame rate policy a new policy which allows switching between all refresh + // rates. case 1036: { - if (data.readInt32() > 0) { - status_t result = - acquireFrameRateFlexibilityToken(&mDebugFrameRateFlexibilityToken); - if (result != NO_ERROR) { - return result; - } - } else { - mDebugFrameRateFlexibilityToken = nullptr; + if (data.readInt32() > 0) { // turn on + return schedule([this] { + const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); + + // This is a little racy, but not in a way that hurts anything. As we + // grab the defaultMode from the display manager policy, we could be + // setting a new display manager policy, leaving us using a stale + // defaultMode. The defaultMode doesn't matter for the override + // policy though, since we set allowGroupSwitching to true, so it's + // not a problem. + scheduler::RefreshRateConfigs::Policy overridePolicy; + overridePolicy.defaultMode = display->refreshRateConfigs() + .getDisplayManagerPolicy() + .defaultMode; + overridePolicy.allowGroupSwitching = true; + constexpr bool kOverridePolicy = true; + return setDesiredDisplayModeSpecsInternal(display, overridePolicy, + kOverridePolicy); + }) + .get(); + } else { // turn off + return schedule([this] { + const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); + constexpr bool kOverridePolicy = true; + return setDesiredDisplayModeSpecsInternal(display, {}, + kOverridePolicy); + }) + .get(); } - return NO_ERROR; } // Inject a hotplug connected event for the primary display. This will deallocate and // reallocate the display state including framebuffers. @@ -6616,74 +6628,6 @@ status_t SurfaceFlinger::setFrameRate(const sp& surface, return NO_ERROR; } -status_t SurfaceFlinger::acquireFrameRateFlexibilityToken(sp* outToken) { - if (!outToken) { - return BAD_VALUE; - } - - auto future = schedule([this] { - status_t result = NO_ERROR; - sp token; - - if (mFrameRateFlexibilityTokenCount == 0) { - const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); - - // This is a little racy, but not in a way that hurts anything. As we grab the - // defaultMode from the display manager policy, we could be setting a new display - // manager policy, leaving us using a stale defaultMode. The defaultMode doesn't - // matter for the override policy though, since we set allowGroupSwitching to - // true, so it's not a problem. - scheduler::RefreshRateConfigs::Policy overridePolicy; - overridePolicy.defaultMode = - display->refreshRateConfigs().getDisplayManagerPolicy().defaultMode; - overridePolicy.allowGroupSwitching = true; - constexpr bool kOverridePolicy = true; - result = setDesiredDisplayModeSpecsInternal(display, overridePolicy, kOverridePolicy); - } - - if (result == NO_ERROR) { - mFrameRateFlexibilityTokenCount++; - // Handing out a reference to the SurfaceFlinger object, as we're doing in the line - // below, is something to consider carefully. The lifetime of the - // FrameRateFlexibilityToken isn't tied to SurfaceFlinger object lifetime, so if this - // SurfaceFlinger object were to be destroyed while the token still exists, the token - // destructor would be accessing a stale SurfaceFlinger reference, and crash. This is ok - // in this case, for two reasons: - // 1. Once SurfaceFlinger::run() is called by main_surfaceflinger.cpp, the only way - // the program exits is via a crash. So we won't have a situation where the - // SurfaceFlinger object is dead but the process is still up. - // 2. The frame rate flexibility token is acquired/released only by CTS tests, so even - // if condition 1 were changed, the problem would only show up when running CTS tests, - // not on end user devices, so we could spot it and fix it without serious impact. - token = new FrameRateFlexibilityToken( - [this]() { onFrameRateFlexibilityTokenReleased(); }); - ALOGD("Frame rate flexibility token acquired. count=%d", - mFrameRateFlexibilityTokenCount); - } - - return std::make_pair(result, token); - }); - - status_t result; - std::tie(result, *outToken) = future.get(); - return result; -} - -void SurfaceFlinger::onFrameRateFlexibilityTokenReleased() { - static_cast(schedule([this] { - LOG_ALWAYS_FATAL_IF(mFrameRateFlexibilityTokenCount == 0, - "Failed tracking frame rate flexibility tokens"); - mFrameRateFlexibilityTokenCount--; - ALOGD("Frame rate flexibility token released. count=%d", mFrameRateFlexibilityTokenCount); - if (mFrameRateFlexibilityTokenCount == 0) { - const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); - constexpr bool kOverridePolicy = true; - status_t result = setDesiredDisplayModeSpecsInternal(display, {}, kOverridePolicy); - LOG_ALWAYS_FATAL_IF(result < 0, "Failed releasing frame rate flexibility token"); - } - })); -} - status_t SurfaceFlinger::setFrameTimelineInfo(const sp& surface, const FrameTimelineInfo& frameTimelineInfo) { Mutex::Autolock lock(mStateLock); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 276c7f6bfe..09cf5cee9d 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -601,7 +601,6 @@ private: float lightPosY, float lightPosZ, float lightRadius) override; status_t setFrameRate(const sp& surface, float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) override; - status_t acquireFrameRateFlexibilityToken(sp* outToken) override; status_t setFrameTimelineInfo(const sp& surface, const FrameTimelineInfo& frameTimelineInfo) override; @@ -1067,8 +1066,6 @@ private: return doDump(fd, args, asProto); } - void onFrameRateFlexibilityTokenReleased(); - static mat4 calculateColorMatrix(float saturation); void updateColorMatrixLocked(); @@ -1335,10 +1332,6 @@ private: // be any issues with a raw pointer referencing an invalid object. std::unordered_set mOffscreenLayers; - int mFrameRateFlexibilityTokenCount = 0; - - sp mDebugFrameRateFlexibilityToken; - BufferCountTracker mBufferCountTracker; std::unordered_map> mHdrLayerInfoListeners -- cgit v1.2.3-59-g8ed1b From 04390376b043bf6a15ff2943a9ed63d9d8173842 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 1 Nov 2021 18:17:23 -0700 Subject: avoid extra release of unowned objects in Parcel error path Another bug due to a huge amount of complexity in the Parcel implementation. Bug: 203847542 Test: added testcase fails on device w/o Parcel.cpp fix, and it passes on a device with the fix Change-Id: I34411675687cb3d18bffa082984ebdf308e1c1a6 --- libs/binder/Parcel.cpp | 8 ++++--- libs/binder/tests/binderLibTest.cpp | 46 ++++++++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 181f4051b7..6f0aa34516 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -2181,12 +2181,14 @@ void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, type == BINDER_TYPE_FD)) { // We should never receive other types (eg BINDER_TYPE_FDA) as long as we don't support // them in libbinder. If we do receive them, it probably means a kernel bug; try to - // recover gracefully by clearing out the objects, and releasing the objects we do - // know about. + // recover gracefully by clearing out the objects. android_errorWriteLog(0x534e4554, "135930648"); + android_errorWriteLog(0x534e4554, "203847542"); ALOGE("%s: unsupported type object (%" PRIu32 ") at offset %" PRIu64 "\n", __func__, type, (uint64_t)offset); - releaseObjects(); + + // WARNING: callers of ipcSetDataReference need to make sure they + // don't rely on mObjectsSize in their release_func. mObjectsSize = 0; break; } diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index c8938998a6..63a4b2cc68 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -112,7 +112,7 @@ enum BinderLibTestTranscationCode { BINDER_LIB_TEST_NOP_TRANSACTION_WAIT, BINDER_LIB_TEST_GETPID, BINDER_LIB_TEST_ECHO_VECTOR, - BINDER_LIB_TEST_REJECT_BUF, + BINDER_LIB_TEST_REJECT_OBJECTS, BINDER_LIB_TEST_CAN_GET_SID, }; @@ -1166,13 +1166,53 @@ TEST_F(BinderLibTest, BufRejected) { memcpy(parcelData, &obj, sizeof(obj)); data.setDataSize(sizeof(obj)); + EXPECT_EQ(data.objectsCount(), 1); + // Either the kernel should reject this transaction (if it's correct), but // if it's not, the server implementation should return an error if it // finds an object in the received Parcel. - EXPECT_THAT(server->transact(BINDER_LIB_TEST_REJECT_BUF, data, &reply), + EXPECT_THAT(server->transact(BINDER_LIB_TEST_REJECT_OBJECTS, data, &reply), Not(StatusEq(NO_ERROR))); } +TEST_F(BinderLibTest, WeakRejected) { + Parcel data, reply; + sp server = addServer(); + ASSERT_TRUE(server != nullptr); + + auto binder = sp::make(); + wp wpBinder(binder); + flat_binder_object obj{ + .hdr = {.type = BINDER_TYPE_WEAK_BINDER}, + .flags = 0, + .binder = reinterpret_cast(wpBinder.get_refs()), + .cookie = reinterpret_cast(wpBinder.unsafe_get()), + }; + data.setDataCapacity(1024); + // Write a bogus object at offset 0 to get an entry in the offset table + data.writeFileDescriptor(0); + EXPECT_EQ(data.objectsCount(), 1); + uint8_t *parcelData = const_cast(data.data()); + // And now, overwrite it with the weak binder + memcpy(parcelData, &obj, sizeof(obj)); + data.setDataSize(sizeof(obj)); + + // a previous bug caused other objects to be released an extra time, so we + // test with an object that libbinder will actually try to release + EXPECT_EQ(OK, data.writeStrongBinder(sp::make())); + + EXPECT_EQ(data.objectsCount(), 2); + + // send it many times, since previous error was memory corruption, make it + // more likely that the server crashes + for (size_t i = 0; i < 100; i++) { + EXPECT_THAT(server->transact(BINDER_LIB_TEST_REJECT_OBJECTS, data, &reply), + StatusEq(BAD_VALUE)); + } + + EXPECT_THAT(server->pingBinder(), StatusEq(NO_ERROR)); +} + TEST_F(BinderLibTest, GotSid) { sp server = addServer(); @@ -1566,7 +1606,7 @@ public: reply->writeUint64Vector(vector); return NO_ERROR; } - case BINDER_LIB_TEST_REJECT_BUF: { + case BINDER_LIB_TEST_REJECT_OBJECTS: { return data.objectsCount() == 0 ? BAD_VALUE : NO_ERROR; } case BINDER_LIB_TEST_CAN_GET_SID: { -- cgit v1.2.3-59-g8ed1b From 4d48f9092b1209ad871969613e37ae19cb506d3c Mon Sep 17 00:00:00 2001 From: ramindani Date: Mon, 20 Sep 2021 21:07:45 +0000 Subject: Latch Unsignaled when only a single layer is being updated. Three conditions are introduced. DISABLED (Default for now): This is when latch unsignaled is completely disabled. AUTO: This is when we will latch for the single layer update. Further refinements will be done in b/200284381 ALWAYS: This will latch unsignaled no matter what the change is. BUG: 198189193 Test: Did the manual test and atest libsurfaceflinger_unittest atest MockFence_test atest libgui_test Change-Id: I0c0b475ba4a093275fac23a986fc610ea462f73e --- libs/ui/include/ui/Fence.h | 2 +- libs/ui/include_mock/ui/MockFence.h | 1 + libs/ui/tests/MockFence_test.cpp | 12 + services/surfaceflinger/BufferQueueLayer.cpp | 2 +- services/surfaceflinger/BufferStateLayer.cpp | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 149 ++++++-- services/surfaceflinger/SurfaceFlinger.h | 15 +- .../tests/unittests/TestableSurfaceFlinger.h | 1 + .../tests/unittests/TransactionApplicationTest.cpp | 416 ++++++++++++++++++++- 9 files changed, 562 insertions(+), 38 deletions(-) diff --git a/libs/ui/include/ui/Fence.h b/libs/ui/include/ui/Fence.h index 7634007771..9aae145c04 100644 --- a/libs/ui/include/ui/Fence.h +++ b/libs/ui/include/ui/Fence.h @@ -124,7 +124,7 @@ public: // getStatus() returns whether the fence has signaled yet. Prefer this to // getSignalTime() or wait() if all you care about is whether the fence has // signaled. - inline Status getStatus() { + virtual inline Status getStatus() { // The sync_wait call underlying wait() has been measured to be // significantly faster than the sync_fence_info call underlying // getSignalTime(), which might otherwise appear to be the more obvious diff --git a/libs/ui/include_mock/ui/MockFence.h b/libs/ui/include_mock/ui/MockFence.h index 162ec02455..71adee4fbc 100644 --- a/libs/ui/include_mock/ui/MockFence.h +++ b/libs/ui/include_mock/ui/MockFence.h @@ -27,6 +27,7 @@ public: virtual ~MockFence() = default; MOCK_METHOD(nsecs_t, getSignalTime, (), (const, override)); + MOCK_METHOD(Status, getStatus, (), (override)); }; }; // namespace android::mock diff --git a/libs/ui/tests/MockFence_test.cpp b/libs/ui/tests/MockFence_test.cpp index 6e520b1aee..40dddc3cf2 100644 --- a/libs/ui/tests/MockFence_test.cpp +++ b/libs/ui/tests/MockFence_test.cpp @@ -42,4 +42,16 @@ TEST_F(MockFenceTest, getSignalTime) { EXPECT_EQ(1234, fence->getSignalTime()); } +TEST_F(MockFenceTest, getStatus) { + sp fence = getFenceForTesting(); + + EXPECT_CALL(getMockFence(), getStatus).WillOnce(Return(Fence::Status::Unsignaled)); + EXPECT_EQ(Fence::Status::Unsignaled, fence->getStatus()); + + EXPECT_CALL(getMockFence(), getStatus).WillOnce(Return(Fence::Status::Signaled)); + EXPECT_EQ(Fence::Status::Signaled, fence->getStatus()); + + EXPECT_CALL(getMockFence(), getStatus).WillOnce(Return(Fence::Status::Invalid)); + EXPECT_EQ(Fence::Status::Invalid, fence->getStatus()); +} } // namespace android::ui diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 4e5d2d03b0..8aecec131f 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -118,7 +118,7 @@ bool BufferQueueLayer::isBufferDue(nsecs_t expectedPresentTime) const { bool BufferQueueLayer::fenceHasSignaled() const { Mutex::Autolock lock(mQueueItemLock); - if (SurfaceFlinger::enableLatchUnsignaled) { + if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) { return true; } diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index c0753f9d47..f7f96ab1b1 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -630,7 +630,7 @@ FloatRect BufferStateLayer::computeSourceBounds(const FloatRect& parentBounds) c // Interface implementation for BufferLayer // ----------------------------------------------------------------------- bool BufferStateLayer::fenceHasSignaled() const { - if (SurfaceFlinger::enableLatchUnsignaled) { + if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) { return true; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8d7221c1dc..9b1677478d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -341,7 +341,7 @@ Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRG ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888; bool SurfaceFlinger::useFrameRateApi; bool SurfaceFlinger::enableSdrDimming; -bool SurfaceFlinger::enableLatchUnsignaled; +LatchUnsignaledConfig SurfaceFlinger::enableLatchUnsignaledConfig; std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) { switch(displayColorSetting) { @@ -501,7 +501,17 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI // Debug property overrides ro. property enableSdrDimming = property_get_bool("debug.sf.enable_sdr_dimming", enable_sdr_dimming(false)); - enableLatchUnsignaled = base::GetBoolProperty("debug.sf.latch_unsignaled"s, false); + enableLatchUnsignaledConfig = getLatchUnsignaledConfig(); +} + +LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() { + if (base::GetBoolProperty("debug.sf.latch_unsignaled"s, false)) { + return LatchUnsignaledConfig::Always; + } else if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, false)) { + return LatchUnsignaledConfig::Auto; + } else { + return LatchUnsignaledConfig::Disabled; + } } SurfaceFlinger::~SurfaceFlinger() = default; @@ -3421,29 +3431,34 @@ uint32_t SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule } bool SurfaceFlinger::flushTransactionQueues() { - bool needsTraversal = false; // to prevent onHandleDestroyed from being called while the lock is held, // we must keep a copy of the transactions (specifically the composer // states) around outside the scope of the lock - std::vector transactions; + std::vector transactions; // Layer handles that have transactions with buffers that are ready to be applied. std::unordered_set, ISurfaceComposer::SpHash> bufferLayersReadyToPresent; { Mutex::Autolock _l(mStateLock); { Mutex::Autolock _l(mQueueLock); + // allowLatchUnsignaled acts as a filter condition when latch unsignaled is either auto + // or always. auto: in this case we let buffer latch unsignaled if we have only one + // applyToken and if only first transaction is latch unsignaled. If more than one + // applyToken we don't latch unsignaled. + bool allowLatchUnsignaled = allowedLatchUnsignaled(); + bool isFirstUnsignaledTransactionApplied = false; // Collect transactions from pending transaction queue. auto it = mPendingTransactionQueues.begin(); while (it != mPendingTransactionQueues.end()) { auto& [applyToken, transactionQueue] = *it; - while (!transactionQueue.empty()) { auto& transaction = transactionQueue.front(); if (!transactionIsReadyToBeApplied(transaction.frameTimelineInfo, transaction.isAutoTimestamp, transaction.desiredPresentTime, transaction.originUid, transaction.states, - bufferLayersReadyToPresent)) { + bufferLayersReadyToPresent, + allowLatchUnsignaled)) { setTransactionFlags(eTransactionFlushNeeded); break; } @@ -3452,6 +3467,14 @@ bool SurfaceFlinger::flushTransactionQueues() { }); transactions.emplace_back(std::move(transaction)); transactionQueue.pop(); + if (allowLatchUnsignaled && + enableLatchUnsignaledConfig == LatchUnsignaledConfig::Auto) { + // if allowLatchUnsignaled && we are in LatchUnsignaledConfig::Auto + // then we should have only one applyToken for processing. + // so we can stop further transactions on this applyToken. + isFirstUnsignaledTransactionApplied = true; + break; + } } if (transactionQueue.empty()) { @@ -3463,52 +3486,115 @@ bool SurfaceFlinger::flushTransactionQueues() { } // Collect transactions from current transaction queue or queue to pending transactions. - // Case 1: push to pending when transactionIsReadyToBeApplied is false. + // Case 1: push to pending when transactionIsReadyToBeApplied is false + // or the first transaction was unsignaled. // Case 2: push to pending when there exist a pending queue. - // Case 3: others are ready to apply. + // Case 3: others are the transactions that are ready to apply. while (!mTransactionQueue.empty()) { auto& transaction = mTransactionQueue.front(); bool pendingTransactions = mPendingTransactionQueues.find(transaction.applyToken) != mPendingTransactionQueues.end(); - if (pendingTransactions || + if (isFirstUnsignaledTransactionApplied || pendingTransactions || !transactionIsReadyToBeApplied(transaction.frameTimelineInfo, transaction.isAutoTimestamp, transaction.desiredPresentTime, transaction.originUid, transaction.states, - bufferLayersReadyToPresent)) { + bufferLayersReadyToPresent, + allowLatchUnsignaled)) { mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction)); } else { transaction.traverseStatesWithBuffers([&](const layer_state_t& state) { bufferLayersReadyToPresent.insert(state.surface); }); transactions.emplace_back(std::move(transaction)); + if (allowLatchUnsignaled && + enableLatchUnsignaledConfig == LatchUnsignaledConfig::Auto) { + isFirstUnsignaledTransactionApplied = true; + } } - mTransactionQueue.pop(); + mTransactionQueue.pop_front(); ATRACE_INT("TransactionQueue", mTransactionQueue.size()); } + + return applyTransactions(transactions); } + } +} - // Now apply all transactions. - for (const auto& transaction : transactions) { - needsTraversal |= - applyTransactionState(transaction.frameTimelineInfo, transaction.states, - transaction.displays, transaction.flags, - transaction.inputWindowCommands, - transaction.desiredPresentTime, - transaction.isAutoTimestamp, transaction.buffer, - transaction.postTime, transaction.permissions, - transaction.hasListenerCallbacks, - transaction.listenerCallbacks, transaction.originPid, - transaction.originUid, transaction.id); - if (transaction.transactionCommittedSignal) { - mTransactionCommittedSignals.emplace_back( - std::move(transaction.transactionCommittedSignal)); - } +bool SurfaceFlinger::applyTransactions(std::vector& transactions) { + bool needsTraversal = false; + // Now apply all transactions. + for (const auto& transaction : transactions) { + needsTraversal |= + applyTransactionState(transaction.frameTimelineInfo, transaction.states, + transaction.displays, transaction.flags, + transaction.inputWindowCommands, + transaction.desiredPresentTime, transaction.isAutoTimestamp, + transaction.buffer, transaction.postTime, + transaction.permissions, transaction.hasListenerCallbacks, + transaction.listenerCallbacks, transaction.originPid, + transaction.originUid, transaction.id); + if (transaction.transactionCommittedSignal) { + mTransactionCommittedSignals.emplace_back( + std::move(transaction.transactionCommittedSignal)); } - } // unlock mStateLock + } return needsTraversal; } +bool SurfaceFlinger::allowedLatchUnsignaled() { + if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) { + return false; + } + // Always mode matches the current latch unsignaled behavior. + // This behavior is currently used by the partners and we would like + // to keep it until we are completely migrated to Auto mode successfully + // and we we have our fallback based implementation in place. + if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Always) { + return true; + } + + // if enableLatchUnsignaledConfig == LatchUnsignaledConfig::Auto + // we don't latch unsignaled if more than one applyToken, as it can backpressure + // the other transactions. + if (mPendingTransactionQueues.size() > 1) { + return false; + } + std::optional> applyToken = std::nullopt; + bool isPendingTransactionQueuesItem = false; + if (!mPendingTransactionQueues.empty()) { + applyToken = mPendingTransactionQueues.begin()->first; + isPendingTransactionQueuesItem = true; + } + + for (const auto& item : mTransactionQueue) { + if (!applyToken.has_value()) { + applyToken = item.applyToken; + } else if (applyToken.has_value() && applyToken != item.applyToken) { + return false; + } + } + + if (isPendingTransactionQueuesItem) { + return checkTransactionCanLatchUnsignaled( + mPendingTransactionQueues.begin()->second.front()); + } else if (applyToken.has_value()) { + return checkTransactionCanLatchUnsignaled((mTransactionQueue.front())); + } + return false; +} + +bool SurfaceFlinger::checkTransactionCanLatchUnsignaled(const TransactionState& transaction) { + if (transaction.states.size() == 1) { + const auto& state = transaction.states.begin()->state; + return (state.flags & ~layer_state_t::eBufferChanged) == 0 && + state.bufferData.flags.test(BufferData::BufferDataChange::fenceChanged) && + state.bufferData.acquireFence && + state.bufferData.acquireFence->getStatus() == Fence::Status::Unsignaled; + } + return false; +} + bool SurfaceFlinger::transactionFlushNeeded() { Mutex::Autolock _l(mQueueLock); return !mPendingTransactionQueues.empty() || !mTransactionQueue.empty(); @@ -3540,7 +3626,8 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied( const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, uid_t originUid, const Vector& states, const std::unordered_set, ISurfaceComposer::SpHash>& - bufferLayersReadyToPresent) const { + bufferLayersReadyToPresent, + bool allowLatchUnsignaled) const { ATRACE_CALL(); const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); // Do not present if the desiredPresentTime has not passed unless it is more than one second @@ -3567,7 +3654,7 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied( const layer_state_t& s = state.state; const bool acquireFenceChanged = s.bufferData.flags.test(BufferData::BufferDataChange::fenceChanged); - if (acquireFenceChanged && s.bufferData.acquireFence && !enableLatchUnsignaled && + if (acquireFenceChanged && s.bufferData.acquireFence && !allowLatchUnsignaled && s.bufferData.acquireFence->getStatus() == Fence::Status::Unsignaled) { ATRACE_NAME("fence unsignaled"); return false; @@ -3628,7 +3715,7 @@ void SurfaceFlinger::queueTransaction(TransactionState& state) { : CountDownLatch::eSyncTransaction)); } - mTransactionQueue.emplace(state); + mTransactionQueue.emplace_back(state); ATRACE_INT("TransactionQueue", mTransactionQueue.size()); const auto schedule = [](uint32_t flags) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 276c7f6bfe..97fddf2930 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -135,6 +135,8 @@ enum { eTransactionMask = 0x1f, }; +enum class LatchUnsignaledConfig { Always, Auto, Disabled }; + using DisplayColorSetting = compositionengine::OutputColorSetting; struct SurfaceFlingerBE { @@ -257,7 +259,7 @@ public: // being treated as native display brightness static bool enableSdrDimming; - static bool enableLatchUnsignaled; + static LatchUnsignaledConfig enableLatchUnsignaledConfig; // must be called before clients can connect void init() ANDROID_API; @@ -751,7 +753,14 @@ private: const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, uid_t originUid, const Vector& states, const std::unordered_set, ISurfaceComposer::SpHash>& - bufferLayersReadyToPresent) const REQUIRES(mStateLock); + bufferLayersReadyToPresent, + bool allowLatchUnsignaled) const REQUIRES(mStateLock); + static LatchUnsignaledConfig getLatchUnsignaledConfig(); + bool latchUnsignaledIsAllowed(std::vector& transactions) REQUIRES(mStateLock); + bool allowedLatchUnsignaled() REQUIRES(mQueueLock, mStateLock); + bool checkTransactionCanLatchUnsignaled(const TransactionState& transaction) + REQUIRES(mStateLock); + bool applyTransactions(std::vector& transactions) REQUIRES(mStateLock); uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock); uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands) REQUIRES(mStateLock); @@ -1242,7 +1251,7 @@ private: Condition mTransactionQueueCV; std::unordered_map, std::queue, IListenerHash> mPendingTransactionQueues GUARDED_BY(mQueueLock); - std::queue mTransactionQueue GUARDED_BY(mQueueLock); + std::deque mTransactionQueue GUARDED_BY(mQueueLock); /* * Feature prototyping */ diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index c23fcc7d58..9832372a86 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -375,6 +375,7 @@ public: auto& getTransactionQueue() { return mFlinger->mTransactionQueue; } auto& getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; } + auto& getTransactionCommittedSignals() { return mFlinger->mTransactionCommittedSignals; } auto setTransactionState( const FrameTimelineInfo& frameTimelineInfo, const Vector& states, diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index 05551b4701..8caadfbf85 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -24,8 +24,8 @@ #include #include #include +#include #include - #include "TestableScheduler.h" #include "TestableSurfaceFlinger.h" #include "mock/MockEventThread.h" @@ -74,6 +74,13 @@ public: EXPECT_CALL(*mVSyncTracker, currentPeriod()) .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); + EXPECT_CALL(*mFenceUnsignaled, getStatus()) + .WillRepeatedly(Return(Fence::Status::Unsignaled)); + EXPECT_CALL(*mFenceUnsignaled2, getStatus()) + .WillRepeatedly(Return(Fence::Status::Unsignaled)); + EXPECT_CALL(*mFenceSignaled, getStatus()).WillRepeatedly(Return(Fence::Status::Signaled)); + EXPECT_CALL(*mFenceSignaled2, getStatus()).WillRepeatedly(Return(Fence::Status::Signaled)); + mFlinger.setupComposer(std::make_unique()); mFlinger.setupScheduler(std::unique_ptr(mVsyncController), std::unique_ptr(mVSyncTracker), @@ -88,6 +95,10 @@ public: mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); mock::VsyncController* mVsyncController = new mock::VsyncController(); mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker(); + mock::MockFence* mFenceUnsignaled = new mock::MockFence(); + mock::MockFence* mFenceSignaled = new mock::MockFence(); + mock::MockFence* mFenceUnsignaled2 = new mock::MockFence(); + mock::MockFence* mFenceSignaled2 = new mock::MockFence(); struct TransactionInfo { Vector states; @@ -124,6 +135,15 @@ public: transaction.frameTimelineInfo = frameTimelineInfo; } + void setupSingleWithComposer(TransactionInfo& transaction, uint32_t flags, + bool syncInputWindows, int64_t desiredPresentTime, + bool isAutoTimestamp, const FrameTimelineInfo& frameTimelineInfo, + const Vector* states) { + setupSingle(transaction, flags, syncInputWindows, desiredPresentTime, isAutoTimestamp, + frameTimelineInfo); + transaction.states = *states; + } + void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) { ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); @@ -245,6 +265,188 @@ public: EXPECT_EQ(0u, transactionQueue.size()); } + void Flush_removesUnsignaledFromTheQueue(Vector state1, + Vector state2, + bool updateApplyToken = true) { + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); + + TransactionInfo transactionA; + setupSingleWithComposer(transactionA, ISurfaceComposer::eSynchronous, + /*syncInputWindows*/ false, + /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, + FrameTimelineInfo{}, &state1); + + mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, + transactionA.displays, transactionA.flags, + transactionA.applyToken, transactionA.inputWindowCommands, + transactionA.desiredPresentTime, transactionA.isAutoTimestamp, + transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transactionA.id); + + TransactionInfo transactionB; + if (updateApplyToken) { + transactionB.applyToken = sp(); + } + setupSingleWithComposer(transactionB, ISurfaceComposer::eSynchronous, + /*syncInputWindows*/ false, + /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, + FrameTimelineInfo{}, &state2); + mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states, + transactionB.displays, transactionB.flags, + transactionB.applyToken, transactionB.inputWindowCommands, + transactionB.desiredPresentTime, transactionB.isAutoTimestamp, + transactionB.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transactionB.id); + + mFlinger.flushTransactionQueues(); + EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); + EXPECT_EQ(0u, mFlinger.getTransactionQueue().size()); + EXPECT_EQ(2ul, mFlinger.getTransactionCommittedSignals().size()); + } + + void Flush_removesFromTheQueue(const Vector& state) { + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); + EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); + + TransactionInfo transaction; + setupSingleWithComposer(transaction, ISurfaceComposer::eSynchronous, + /*syncInputWindows*/ false, + /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, + FrameTimelineInfo{}, &state); + + mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states, + transaction.displays, transaction.flags, + transaction.applyToken, transaction.inputWindowCommands, + transaction.desiredPresentTime, transaction.isAutoTimestamp, + transaction.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transaction.id); + + mFlinger.flushTransactionQueues(); + EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); + EXPECT_EQ(0u, mFlinger.getTransactionQueue().size()); + EXPECT_EQ(1u, mFlinger.getTransactionCommittedSignals().size()); + } + + void Flush_keepsInTheQueue(const Vector& state) { + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); + EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); + + TransactionInfo transaction; + setupSingleWithComposer(transaction, ISurfaceComposer::eSynchronous, + /*syncInputWindows*/ false, + /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, + FrameTimelineInfo{}, &state); + + mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states, + transaction.displays, transaction.flags, + transaction.applyToken, transaction.inputWindowCommands, + transaction.desiredPresentTime, transaction.isAutoTimestamp, + transaction.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transaction.id); + + mFlinger.flushTransactionQueues(); + EXPECT_EQ(1u, mFlinger.getPendingTransactionQueue().size()); + EXPECT_EQ(0u, mFlinger.getTransactionQueue().size()); + EXPECT_EQ(0ul, mFlinger.getTransactionCommittedSignals().size()); + } + + void Flush_KeepsUnsignaledInTheQueue(const Vector& state1, + const Vector& state2, + bool updateApplyToken = true, + uint32_t pendingTransactionQueueSize = 1u) { + EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); + auto time = systemTime(); + TransactionInfo transactionA; + TransactionInfo transactionB; + setupSingleWithComposer(transactionA, ISurfaceComposer::eSynchronous, + /*syncInputWindows*/ false, + /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true, + FrameTimelineInfo{}, &state1); + setupSingleWithComposer(transactionB, ISurfaceComposer::eSynchronous, + /*syncInputWindows*/ false, + /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true, + FrameTimelineInfo{}, &state2); + mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, + transactionA.displays, transactionA.flags, + transactionA.applyToken, transactionA.inputWindowCommands, + transactionA.desiredPresentTime, transactionA.isAutoTimestamp, + transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transactionA.id); + if (updateApplyToken) { + transactionB.applyToken = sp(); + } + mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states, + transactionB.displays, transactionB.flags, + transactionB.applyToken, transactionB.inputWindowCommands, + transactionB.desiredPresentTime, transactionB.isAutoTimestamp, + transactionB.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transactionB.id); + + mFlinger.flushTransactionQueues(); + EXPECT_EQ(pendingTransactionQueueSize, mFlinger.getPendingTransactionQueue().size()); + EXPECT_EQ(0u, mFlinger.getTransactionQueue().size()); + } + + void Flush_removesSignaledFromTheQueue(const Vector& state1, + const Vector& state2) { + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); + EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); + + auto time = systemTime(); + TransactionInfo transactionA; + TransactionInfo transactionB; + setupSingleWithComposer(transactionA, ISurfaceComposer::eSynchronous, + /*syncInputWindows*/ false, + /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true, + FrameTimelineInfo{}, &state1); + setupSingleWithComposer(transactionB, ISurfaceComposer::eSynchronous, + /*syncInputWindows*/ false, + /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true, + FrameTimelineInfo{}, &state2); + mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, + transactionA.displays, transactionA.flags, + transactionA.applyToken, transactionA.inputWindowCommands, + transactionA.desiredPresentTime, transactionA.isAutoTimestamp, + transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transactionA.id); + mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states, + transactionB.displays, transactionB.flags, + transactionB.applyToken, transactionB.inputWindowCommands, + transactionB.desiredPresentTime, transactionB.isAutoTimestamp, + transactionB.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transactionB.id); + + mFlinger.flushTransactionQueues(); + EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); + EXPECT_EQ(0u, mFlinger.getTransactionQueue().size()); + EXPECT_EQ(2ul, mFlinger.getTransactionCommittedSignals().size()); + } + + static Vector createComposerStateVector(const ComposerState& state1, + const ComposerState& state2) { + Vector states; + states.push_back(state1); + states.push_back(state2); + return states; + } + + static Vector createComposerStateVector(const ComposerState& state) { + Vector states; + states.push_back(state); + return states; + } + + static ComposerState createComposerState(int layerId, sp fence, + uint32_t stateFlags = layer_state_t::eBufferChanged) { + ComposerState composer_state; + composer_state.state.bufferData.acquireFence = std::move(fence); + composer_state.state.layerId = layerId; + composer_state.state.bufferData.flags = BufferData::BufferDataChange::fenceChanged; + composer_state.state.flags = stateFlags; + return composer_state; + } + bool mHasListenerCallbacks = false; std::vector mCallbacks; int mTransactionNumber = 0; @@ -327,4 +529,216 @@ TEST_F(TransactionApplicationTest, FromHandle) { auto ret = mFlinger.fromHandle(badHandle); EXPECT_EQ(nullptr, ret.promote().get()); } + +TEST_F(TransactionApplicationTest, Flush_RemovesSingleSignaledFromTheQueue_LatchUnsignaled_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_removesFromTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceSignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_RemovesSingleUnSignaledFromTheQueue_LatchUnsignaled_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_removesFromTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled))); +} + +TEST_F(TransactionApplicationTest, + Flush_KeepsUnSignaledInTheQueue_NonBufferCropChange_LatchUnsignaled_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_keepsInTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceUnsignaled, layer_state_t::eCropChanged))); +} + +TEST_F(TransactionApplicationTest, + Flush_KeepsUnSignaledInTheQueue_NonBufferChangeClubed_LatchUnsignaled_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_keepsInTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceUnsignaled, + layer_state_t::eCropChanged | layer_state_t::eBufferChanged))); +} + +TEST_F(TransactionApplicationTest, + Flush_KeepsInTheQueueSameApplyTokenMultiState_LatchUnsignaled_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_keepsInTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled), + createComposerState(/*layerId*/ 1, mFenceSignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueue_MultipleStateTransaction_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_keepsInTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled), + createComposerState(/*layerId*/ 2, mFenceSignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnsignaled_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_removesSignaledFromTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceSignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceSignaled2))); +} + +TEST_F(TransactionApplicationTest, Flush_RemoveSignaledWithUnsignaledIntact_LatchUnsignaled_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_KeepsUnsignaledInTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceSignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceUnsignaled))); + EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size()); +} + +TEST_F(TransactionApplicationTest, + Flush_KeepsTransactionInTheQueueSameApplyToken_LatchUnsignaled_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_KeepsUnsignaledInTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceUnsignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceSignaled)), + /*updateApplyToken*/ false); + EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size()); +} + +TEST_F(TransactionApplicationTest, Flush_KeepsTransactionInTheQueue_LatchUnsignaled_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_KeepsUnsignaledInTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceUnsignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceUnsignaled)), + /*updateApplyToken*/ true, + /*pendingTransactionQueueSize*/ 2u); + EXPECT_EQ(0ul, mFlinger.getTransactionCommittedSignals().size()); +} + +TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnsignaled_Disabled) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; + Flush_removesFromTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceSignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueue_LatchUnsignaled_Disabled) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; + Flush_keepsInTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueueSameLayerId_LatchUnsignaled_Disabled) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; + Flush_keepsInTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled), + createComposerState(/*layerId*/ 1, mFenceUnsignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueueDifferentLayerId_LatchUnsignaled_Disabled) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; + Flush_keepsInTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled), + createComposerState(/*layerId*/ 2, mFenceUnsignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnSignaled_Disabled) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; + Flush_removesSignaledFromTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceSignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceSignaled2))); +} + +TEST_F(TransactionApplicationTest, + Flush_KeepInTheQueueDifferentApplyToken_LatchUnsignaled_Disabled) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; + Flush_KeepsUnsignaledInTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceUnsignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceSignaled))); + EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size()); +} + +TEST_F(TransactionApplicationTest, Flush_KeepInTheQueueSameApplyToken_LatchUnsignaled_Disabled) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; + Flush_KeepsUnsignaledInTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceSignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceUnsignaled)), + /*updateApplyToken*/ false); + EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size()); +} + +TEST_F(TransactionApplicationTest, Flush_KeepInTheUnsignaledTheQueue_LatchUnsignaled_Disabled) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; + Flush_KeepsUnsignaledInTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceUnsignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceUnsignaled)), + /*updateApplyToken*/ false); + EXPECT_EQ(0ul, mFlinger.getTransactionCommittedSignals().size()); +} + +TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnsignaled_Always) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; + Flush_removesFromTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceSignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_RemovesFromTheQueue_LatchUnsignaled_Always) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; + Flush_removesFromTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_RemovesFromTheQueueSameLayerId_LatchUnsignaled_Always) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; + Flush_removesFromTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled), + createComposerState(/*layerId*/ 1, mFenceSignaled))); +} + +TEST_F(TransactionApplicationTest, + Flush_RemovesFromTheQueueDifferentLayerId_LatchUnsignaled_Always) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; + Flush_removesFromTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled), + createComposerState(/*layerId*/ 2, mFenceSignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnSignaled_Always) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; + Flush_removesSignaledFromTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceSignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceSignaled2))); +} + +TEST_F(TransactionApplicationTest, + Flush_RemovesFromTheQueueDifferentApplyToken_LatchUnsignaled_Always) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; + Flush_removesUnsignaledFromTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceSignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, + mFenceUnsignaled))); +} + +TEST_F(TransactionApplicationTest, + Flush_RemovesUnsignaledFromTheQueueSameApplyToken_LatchUnsignaled_Always) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; + Flush_removesUnsignaledFromTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, + mFenceUnsignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceSignaled)), + /*updateApplyToken*/ false); +} + +TEST_F(TransactionApplicationTest, Flush_RemovesUnsignaledFromTheQueue_LatchUnsignaled_Always) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; + Flush_removesUnsignaledFromTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, + mFenceUnsignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, + mFenceUnsignaled))); +} + } // namespace android -- cgit v1.2.3-59-g8ed1b From a63f9ae700ee065192b1d249a9e8c190cd3a6440 Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Wed, 3 Nov 2021 15:05:16 +0100 Subject: SF: remove changeRefreshRateLocked Remove changeRefreshRateLocked which is used only in one place. Bug: 190982486 Test: presubmit Change-Id: Ia16b90c46c84c491caf8fff8dfe8f2f0b6335bbd --- services/surfaceflinger/SurfaceFlinger.cpp | 34 +++++++++++++----------------- services/surfaceflinger/SurfaceFlinger.h | 6 +----- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6bd5b01660..aedebaed3a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1766,24 +1766,6 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { *compositorTiming = getBE().mCompositorTiming; } -void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate, - Scheduler::ModeEvent event) { - const auto display = getDefaultDisplayDeviceLocked(); - if (!display || mBootStage != BootStage::FINISHED) { - return; - } - ATRACE_CALL(); - - // Don't do any updating if the current fps is the same as the new one. - if (!display->refreshRateConfigs().isModeAllowed(refreshRate.getModeId())) { - ALOGV("Skipping mode %d as it is not part of allowed modes", - refreshRate.getModeId().value()); - return; - } - - setDesiredActiveMode({refreshRate.getMode(), event}); -} - void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, hal::Connection connection) { const bool connected = connection == hal::Connection::CONNECTED; @@ -3113,7 +3095,21 @@ void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate, Scheduler // Scheduler::chooseRefreshRateForContent ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId); - changeRefreshRateLocked(refreshRate, event); + + const auto display = getDefaultDisplayDeviceLocked(); + if (!display || mBootStage != BootStage::FINISHED) { + return; + } + ATRACE_CALL(); + + // Don't do any updating if the current fps is the same as the new one. + if (!display->refreshRateConfigs().isModeAllowed(refreshRate.getModeId())) { + ALOGV("Skipping mode %d as it is not part of allowed modes", + refreshRate.getModeId().value()); + return; + } + + setDesiredActiveMode({refreshRate.getMode(), event}); } void SurfaceFlinger::triggerOnFrameRateOverridesChanged() { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 09cf5cee9d..22348b4baf 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -648,7 +648,7 @@ private: // Toggles hardware VSYNC by calling into HWC. void setVsyncEnabled(bool) override; - // Initiates a refresh rate change to be applied on invalidate. + // Initiates a refresh rate change to be applied on commit. void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override; // Called when kernel idle timer has expired. Used to update the refresh rate overlay. void kernelTimerChanged(bool expired) override; @@ -951,10 +951,6 @@ private: getHwComposer().setVsyncEnabled(id, enabled); } - // Sets the refresh rate by switching active configs, if they are available for - // the desired refresh rate. - void changeRefreshRateLocked(const RefreshRate&, Scheduler::ModeEvent) REQUIRES(mStateLock); - struct FenceWithFenceTime { sp fence = Fence::NO_FENCE; std::shared_ptr fenceTime = FenceTime::NO_FENCE; -- cgit v1.2.3-59-g8ed1b From 3f0286607e9d35196fdff27f84381dffb7bafcad Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Thu, 4 Nov 2021 19:32:24 +0000 Subject: Revert "Revert "Send multiple scheduler frame timelines."" This reverts commit caaa47d60b83670206dcd3c34382719b1f247ab5. Reason for revert: Fix the reverted CL in 2nd CL. Bug: 198192508 Bug: 204941507 Test: See 2nd CL. Change-Id: I15c693c2e0a82ef81a490319da11871bd74298b3 --- libs/gui/DisplayEventDispatcher.cpp | 16 +++++++ libs/gui/include/gui/DisplayEventDispatcher.h | 24 ++++++++++ libs/gui/include/gui/DisplayEventReceiver.h | 9 ++++ libs/nativedisplay/AChoreographer.cpp | 34 +++++---------- services/surfaceflinger/Scheduler/EventThread.cpp | 45 +++++++++++++++---- services/surfaceflinger/Scheduler/EventThread.h | 4 ++ .../tests/unittests/EventThreadTest.cpp | 51 +++++++++++++++++++++- 7 files changed, 150 insertions(+), 33 deletions(-) diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp index 6f1a7aed9c..c986b82fd8 100644 --- a/libs/gui/DisplayEventDispatcher.cpp +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -130,6 +130,19 @@ int DisplayEventDispatcher::handleEvent(int, int events, void*) { return 1; // keep the callback } +void DisplayEventDispatcher::populateFrameTimelines(const DisplayEventReceiver::Event& event, + VsyncEventData* outVsyncEventData) const { + for (size_t i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) { + DisplayEventReceiver::Event::VSync::FrameTimeline receiverTimeline = + event.vsync.frameTimelines[i]; + outVsyncEventData->frameTimelines[i] = {.id = receiverTimeline.vsyncId, + .deadlineTimestamp = + receiverTimeline.deadlineTimestamp, + .expectedPresentTime = + receiverTimeline.expectedVSyncTimestamp}; + } +} + bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, uint32_t* outCount, @@ -154,6 +167,9 @@ bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp; outVsyncEventData->frameInterval = ev.vsync.frameInterval; outVsyncEventData->expectedPresentTime = ev.vsync.expectedVSyncTimestamp; + outVsyncEventData->preferredFrameTimelineIndex = + ev.vsync.preferredFrameTimelineIndex; + populateFrameTimelines(ev, outVsyncEventData); break; case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected); diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h index f3bd139e8c..92c89b8bde 100644 --- a/libs/gui/include/gui/DisplayEventDispatcher.h +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -17,6 +17,7 @@ #include #include #include +#include namespace android { using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; @@ -36,6 +37,26 @@ struct VsyncEventData { // The anticipated Vsync present time. int64_t expectedPresentTime = 0; + + struct FrameTimeline { + // The Vsync Id corresponsing to this vsync event. This will be used to + // populate ISurfaceComposer::setFrameTimelineVsync and + // SurfaceComposerClient::setFrameTimelineVsync + int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID; + + // The deadline in CLOCK_MONOTONIC that the app needs to complete its + // frame by (both on the CPU and the GPU) + int64_t deadlineTimestamp = std::numeric_limits::max(); + + // The anticipated Vsync present time. + int64_t expectedPresentTime = 0; + }; + + // Sorted possible frame timelines. + std::array frameTimelines; + + // Index into the frameTimelines that represents the platform's preferred frame timeline. + size_t preferredFrameTimelineIndex = std::numeric_limits::max(); }; class DisplayEventDispatcher : public LooperCallback { @@ -77,5 +98,8 @@ private: bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, uint32_t* outCount, VsyncEventData* outVsyncEventData); + + void populateFrameTimelines(const DisplayEventReceiver::Event& event, + VsyncEventData* outVsyncEventData) const; }; } // namespace android diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index 0dffbde88a..ca368433b1 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -49,6 +49,9 @@ static inline constexpr uint32_t fourcc(char c1, char c2, char c3, char c4) { // ---------------------------------------------------------------------------- class DisplayEventReceiver { public: + // Max amount of frame timelines is arbitrarily set to be reasonable. + static constexpr int64_t kFrameTimelinesLength = 7; + enum { DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'), DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'), @@ -77,6 +80,12 @@ public: nsecs_t deadlineTimestamp __attribute__((aligned(8))); nsecs_t frameInterval __attribute__((aligned(8))); int64_t vsyncId; + size_t preferredFrameTimelineIndex __attribute__((aligned(8))); + struct FrameTimeline { + nsecs_t expectedVSyncTimestamp __attribute__((aligned(8))); + nsecs_t deadlineTimestamp __attribute__((aligned(8))); + int64_t vsyncId; + } frameTimelines[kFrameTimelinesLength]; }; struct Hotplug { diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index 79d9b9313c..fc9680babb 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -100,17 +100,10 @@ class Choreographer; * Implementation of AChoreographerFrameCallbackData. */ struct ChoreographerFrameCallbackDataImpl { - struct FrameTimeline { - int64_t vsyncId{0}; - int64_t expectedPresentTimeNanos{0}; - int64_t deadlineNanos{0}; - }; - int64_t frameTimeNanos{0}; - size_t frameTimelinesLength; - - std::vector frameTimelines; + std::array + frameTimelines; size_t preferredFrameTimelineIndex; @@ -456,14 +449,9 @@ bool Choreographer::inCallback() const { } ChoreographerFrameCallbackDataImpl Choreographer::createFrameCallbackData(nsecs_t timestamp) const { - std::vector frameTimelines; - frameTimelines.push_back({.vsyncId = mLastVsyncEventData.id, - .expectedPresentTimeNanos = mLastVsyncEventData.expectedPresentTime, - .deadlineNanos = mLastVsyncEventData.deadlineTimestamp}); return {.frameTimeNanos = timestamp, - .frameTimelinesLength = 1, - .preferredFrameTimelineIndex = 0, - .frameTimelines = frameTimelines, + .preferredFrameTimelineIndex = mLastVsyncEventData.preferredFrameTimelineIndex, + .frameTimelines = mLastVsyncEventData.frameTimelines, .choreographer = this}; } @@ -646,7 +634,7 @@ size_t AChoreographerFrameCallbackData_getFrameTimelinesLength( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - return frameCallbackData->frameTimelinesLength; + return frameCallbackData->frameTimelines.size(); } size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex( const AChoreographerFrameCallbackData* data) { @@ -662,8 +650,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineVsyncId( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds"); - return frameCallbackData->frameTimelines[index].vsyncId; + LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); + return frameCallbackData->frameTimelines[index].id; } int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime( const AChoreographerFrameCallbackData* data, size_t index) { @@ -671,8 +659,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds"); - return frameCallbackData->frameTimelines[index].expectedPresentTimeNanos; + LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); + return frameCallbackData->frameTimelines[index].expectedPresentTime; } int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline( const AChoreographerFrameCallbackData* data, size_t index) { @@ -680,8 +668,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds"); - return frameCallbackData->frameTimelines[index].deadlineNanos; + LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); + return frameCallbackData->frameTimelines[index].deadlineTimestamp; } AChoreographer* AChoreographer_create() { diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 2bdcaf6ad0..e07eae79c8 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -355,14 +355,7 @@ void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp std::lock_guard lock(mMutex); LOG_FATAL_IF(!mVSyncState); - const int64_t vsyncId = [&] { - if (mTokenManager != nullptr) { - return mTokenManager->generateTokenForPredictions( - {timestamp, deadlineTimestamp, expectedVSyncTimestamp}); - } - return FrameTimelineInfo::INVALID_VSYNC_ID; - }(); - + const int64_t vsyncId = generateToken(timestamp, deadlineTimestamp, expectedVSyncTimestamp); mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count, expectedVSyncTimestamp, deadlineTimestamp, vsyncId)); mCondition.notify_all(); @@ -567,12 +560,48 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, } } +int64_t EventThread::generateToken(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, + nsecs_t deadlineTimestamp) const { + if (mTokenManager != nullptr) { + return mTokenManager->generateTokenForPredictions( + {timestamp, deadlineTimestamp, expectedVSyncTimestamp}); + } + return FrameTimelineInfo::INVALID_VSYNC_ID; +} + +void EventThread::generateFrameTimeline(DisplayEventReceiver::Event& event) const { + // Add 1 to ensure the preferredFrameTimelineIndex entry (when multiplier == 0) is included. + for (int multiplier = -DisplayEventReceiver::kFrameTimelinesLength + 1, currentIndex = 0; + currentIndex < DisplayEventReceiver::kFrameTimelinesLength; multiplier++) { + nsecs_t deadline = event.vsync.deadlineTimestamp + multiplier * event.vsync.frameInterval; + // Valid possible frame timelines must have future values. + if (deadline > event.header.timestamp) { + if (multiplier == 0) { + event.vsync.preferredFrameTimelineIndex = currentIndex; + event.vsync.frameTimelines[currentIndex] = + {.vsyncId = event.vsync.vsyncId, + .deadlineTimestamp = event.vsync.deadlineTimestamp, + .expectedVSyncTimestamp = event.vsync.expectedVSyncTimestamp}; + } else { + nsecs_t expectedVSync = + event.vsync.expectedVSyncTimestamp + multiplier * event.vsync.frameInterval; + event.vsync.frameTimelines[currentIndex] = + {.vsyncId = generateToken(event.header.timestamp, expectedVSync, deadline), + .deadlineTimestamp = deadline, + .expectedVSyncTimestamp = expectedVSync}; + } + currentIndex++; + } + } +} + void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event, const DisplayEventConsumers& consumers) { for (const auto& consumer : consumers) { DisplayEventReceiver::Event copy = event; if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { copy.vsync.frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid); + generateFrameTimeline(copy); } switch (consumer->postEvent(copy)) { case NO_ERROR: diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 9265a25b86..73ae5dc9e3 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -204,6 +204,10 @@ private: void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, nsecs_t deadlineTimestamp) override; + int64_t generateToken(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, + nsecs_t deadlineTimestamp) const; + void generateFrameTimeline(DisplayEventReceiver::Event& event) const; + const std::unique_ptr mVSyncSource GUARDED_BY(mMutex); frametimeline::TokenManager* const mTokenManager; diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index 28d0222829..cb690aa0e4 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -28,6 +28,7 @@ #include "AsyncCallRecorder.h" #include "DisplayHardware/DisplayMode.h" +#include "FrameTimeline.h" #include "Scheduler/EventThread.h" using namespace std::chrono_literals; @@ -96,6 +97,8 @@ protected: ConnectionEventRecorder& connectionEventRecorder, nsecs_t expectedTimestamp, unsigned expectedCount); void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount); + void expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp, + nsecs_t preferredDeadline); void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, bool expectedConnected); void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, @@ -120,6 +123,7 @@ protected: std::unique_ptr mThread; sp mConnection; sp mThrottledConnection; + std::unique_ptr mTokenManager; static constexpr uid_t mConnectionUid = 443; static constexpr uid_t mThrottledConnectionUid = 177; @@ -173,8 +177,8 @@ void EventThreadTest::createThread(std::unique_ptr source) { return VSYNC_PERIOD.count(); }; - mThread = std::make_unique(std::move(source), - /*tokenManager=*/nullptr, + mTokenManager = std::make_unique(); + mThread = std::make_unique(std::move(source), mTokenManager.get(), mInterceptVSyncCallRecorder.getInvocable(), throttleVsync, getVsyncPeriod); @@ -247,6 +251,36 @@ void EventThreadTest::expectVsyncEventReceivedByConnection(nsecs_t expectedTimes expectedCount); } +void EventThreadTest::expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp, + nsecs_t preferredDeadline) { + auto args = mConnectionEventCallRecorder.waitForCall(); + ASSERT_TRUE(args.has_value()) << " did not receive an event for timestamp " + << expectedTimestamp; + const auto& event = std::get<0>(args.value()); + for (int i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) { + if (i > 0) { + EXPECT_GT(event.vsync.frameTimelines[i].deadlineTimestamp, + event.vsync.frameTimelines[i - 1].deadlineTimestamp) + << "Deadline timestamp out of order for frame timeline " << i; + EXPECT_GT(event.vsync.frameTimelines[i].expectedVSyncTimestamp, + event.vsync.frameTimelines[i - 1].expectedVSyncTimestamp) + << "Expected vsync timestamp out of order for frame timeline " << i; + } + if (event.vsync.frameTimelines[i].deadlineTimestamp == preferredDeadline) { + EXPECT_EQ(i, event.vsync.preferredFrameTimelineIndex) + << "Preferred frame timeline index should be " << i; + // For the platform-preferred frame timeline, the vsync ID is 0 because the first frame + // timeline is made before the rest. + EXPECT_EQ(0, event.vsync.frameTimelines[i].vsyncId) + << "Vsync ID incorrect for frame timeline " << i; + } else { + // Vsync ID 0 is used for the preferred frame timeline. + EXPECT_EQ(i + 1, event.vsync.frameTimelines[i].vsyncId) + << "Vsync ID incorrect for frame timeline " << i; + } + } +} + void EventThreadTest::expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, bool expectedConnected) { auto args = mConnectionEventCallRecorder.waitForCall(); @@ -344,6 +378,19 @@ TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) { expectVSyncSetEnabledCallReceived(false); } +TEST_F(EventThreadTest, requestNextVsyncEventFrameTimelinesCorrect) { + // Signal that we want the next vsync event to be posted to the connection + mThread->requestNextVsync(mConnection); + + expectVSyncSetEnabledCallReceived(true); + + // Use the received callback to signal a vsync event. + // The interceptor should receive the event, as well as the connection. + mCallback->onVSyncEvent(123, 456, 789); + expectInterceptCallReceived(123); + expectVsyncEventFrameTimelinesCorrect(123, 789); +} + TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) { // Create a first connection, register it, and request a vsync rate of zero. ConnectionEventRecorder firstConnectionEventRecorder{0}; -- cgit v1.2.3-59-g8ed1b From 8d0c61014f716f945ee64415e95bdd28365320a0 Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Wed, 3 Nov 2021 22:00:25 +0000 Subject: Send multiple scheduler frame timelines (fix). Fix the revert and added extra unit test asserts (fail on previous CL but passes on this CL!!). Bug: 198192508 Bug: 204941507 Test: atest EventThreadTest; atest ChoreographerNativeTest Change-Id: Ib9d8df901fab72cae2cee86692d983c6e02d9c2c --- services/surfaceflinger/Scheduler/EventThread.cpp | 6 +++--- services/surfaceflinger/Scheduler/EventThread.h | 4 ++-- services/surfaceflinger/tests/unittests/EventThreadTest.cpp | 9 +++++++++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index e07eae79c8..455289ff96 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -560,8 +560,8 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, } } -int64_t EventThread::generateToken(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, - nsecs_t deadlineTimestamp) const { +int64_t EventThread::generateToken(nsecs_t timestamp, nsecs_t deadlineTimestamp, + nsecs_t expectedVSyncTimestamp) const { if (mTokenManager != nullptr) { return mTokenManager->generateTokenForPredictions( {timestamp, deadlineTimestamp, expectedVSyncTimestamp}); @@ -586,7 +586,7 @@ void EventThread::generateFrameTimeline(DisplayEventReceiver::Event& event) cons nsecs_t expectedVSync = event.vsync.expectedVSyncTimestamp + multiplier * event.vsync.frameInterval; event.vsync.frameTimelines[currentIndex] = - {.vsyncId = generateToken(event.header.timestamp, expectedVSync, deadline), + {.vsyncId = generateToken(event.header.timestamp, deadline, expectedVSync), .deadlineTimestamp = deadline, .expectedVSyncTimestamp = expectedVSync}; } diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 73ae5dc9e3..de435708a6 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -204,8 +204,8 @@ private: void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, nsecs_t deadlineTimestamp) override; - int64_t generateToken(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, - nsecs_t deadlineTimestamp) const; + int64_t generateToken(nsecs_t timestamp, nsecs_t deadlineTimestamp, + nsecs_t expectedVSyncTimestamp) const; void generateFrameTimeline(DisplayEventReceiver::Event& event) const; const std::unique_ptr mVSyncSource GUARDED_BY(mMutex); diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index cb690aa0e4..67a0d7ec32 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -258,6 +258,15 @@ void EventThreadTest::expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTime << expectedTimestamp; const auto& event = std::get<0>(args.value()); for (int i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) { + auto prediction = + mTokenManager->getPredictionsForToken(event.vsync.frameTimelines[i].vsyncId); + EXPECT_TRUE(prediction.has_value()); + EXPECT_EQ(prediction.value().endTime, event.vsync.frameTimelines[i].deadlineTimestamp) + << "Deadline timestamp does not match cached value"; + EXPECT_EQ(prediction.value().presentTime, + event.vsync.frameTimelines[i].expectedVSyncTimestamp) + << "Expected vsync timestamp does not match cached value"; + if (i > 0) { EXPECT_GT(event.vsync.frameTimelines[i].deadlineTimestamp, event.vsync.frameTimelines[i - 1].deadlineTimestamp) -- cgit v1.2.3-59-g8ed1b From da1fd1508c914c7f0849e4e00a5fae5412433337 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 18 Oct 2021 09:36:33 -0700 Subject: SurfaceFlinger: Emit callbacks for non-buffer layer transactions Ensure we emit callbacks if the transaction contains only non-buffer layer state changes. Test: atest SurfaceFlinger_test Fixes: 205183085 Change-Id: I56bf0dcaff4312628fe2cd1d0b93db520518ec54 --- services/surfaceflinger/BufferStateLayer.cpp | 15 ++++++-- services/surfaceflinger/BufferStateLayer.h | 3 +- services/surfaceflinger/Layer.cpp | 11 ++++++ services/surfaceflinger/Layer.h | 6 +-- services/surfaceflinger/SurfaceFlinger.cpp | 21 +++++----- .../surfaceflinger/TransactionCallbackInvoker.cpp | 8 ++-- .../surfaceflinger/TransactionCallbackInvoker.h | 12 +++--- .../surfaceflinger/tests/LayerCallback_test.cpp | 45 +++++++++++++++++++++- 8 files changed, 89 insertions(+), 32 deletions(-) diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index c213570c7f..3e09a40eba 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -549,13 +549,19 @@ bool BufferStateLayer::setSidebandStream(const sp& sidebandStream) } bool BufferStateLayer::setTransactionCompletedListeners( - const std::vector>& handles) { + const std::vector& listenerCallbacks, const sp& layerHandle) { // If there is no handle, we will not send a callback so reset mReleasePreviousBuffer and return - if (handles.empty()) { + if (listenerCallbacks.empty()) { mReleasePreviousBuffer = false; return false; } + std::vector> handles; + handles.reserve(listenerCallbacks.size()); + for (auto& [listener, callbackIds] : listenerCallbacks) { + handles.emplace_back(new CallbackHandle(listener, callbackIds, layerHandle)); + } + const bool willPresent = willPresentCurrentTransaction(); for (const auto& handle : handles) { @@ -571,9 +577,10 @@ bool BufferStateLayer::setTransactionCompletedListeners( // Store so latched time and release fence can be set mDrawingState.callbackHandles.push_back(handle); - } else { // If this layer will NOT need to be relatched and presented this frame + } else { + // If this layer will NOT need to be relatched and presented this frame // Notify the transaction completed thread this handle is done - mFlinger->getTransactionCallbackInvoker().registerUnpresentedCallbackHandle(handle); + mFlinger->getTransactionCallbackInvoker().addUnpresentedCallbackHandle(handle); } } diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index eea700cf7b..ceed188f0e 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -65,7 +65,8 @@ public: bool setSurfaceDamageRegion(const Region& surfaceDamage) override; bool setApi(int32_t api) override; bool setSidebandStream(const sp& sidebandStream) override; - bool setTransactionCompletedListeners(const std::vector>& handles) override; + bool setTransactionCompletedListeners(const std::vector& handles, + const sp& layerHandle) override; bool addFrameEvent(const sp& acquireFence, nsecs_t postedTime, nsecs_t requestedPresentTime) override; bool setPosition(float /*x*/, float /*y*/) override; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d68cf9720f..d8854d3033 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2645,6 +2645,17 @@ bool Layer::setDropInputMode(gui::DropInputMode mode) { return true; } +bool Layer::setTransactionCompletedListeners( + const std::vector& listenerCallbacks, const sp&) { + if (listenerCallbacks.empty()) { + return false; + } + for (auto& listener : listenerCallbacks) { + mFlinger->getTransactionCallbackInvoker().addEmptyCallback(listener); + } + return false; +} + // --------------------------------------------------------------------------- std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 4569f9af23..f6f162128f 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -426,10 +426,8 @@ public: virtual bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/) { return false; }; virtual bool setApi(int32_t /*api*/) { return false; }; virtual bool setSidebandStream(const sp& /*sidebandStream*/) { return false; }; - virtual bool setTransactionCompletedListeners( - const std::vector>& /*handles*/) { - return false; - }; + virtual bool setTransactionCompletedListeners(const std::vector& /*handles*/, + const sp& /* layerHandle */); virtual bool addFrameEvent(const sp& /*acquireFence*/, nsecs_t /*postedTime*/, nsecs_t /*requestedPresentTime*/) { return false; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 53a4ae02eb..af6d00041e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3727,11 +3727,10 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin transactionFlags |= setDisplayStateLocked(display); } - // start and end registration for listeners w/ no surface so they can get their callback. Note - // that listeners with SurfaceControls will start registration during setClientStateLocked - // below. + // Add listeners w/ surfaces so they can get their callback. Note that listeners with + // SurfaceControls will start registration during setClientStateLocked below. for (const auto& listener : listenerCallbacks) { - mTransactionCallbackInvoker.addEmptyTransaction(listener); + mTransactionCallbackInvoker.addEmptyCallback(listener); } uint32_t clientStateFlags = 0; @@ -3903,7 +3902,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime } if (layer == nullptr) { for (auto& [listener, callbackIds] : s.listeners) { - mTransactionCallbackInvoker.registerUnpresentedCallbackHandle( + mTransactionCallbackInvoker.addUnpresentedCallbackHandle( new CallbackHandle(listener, callbackIds, s.surface)); } return 0; @@ -4173,12 +4172,6 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime flags |= eTransactionNeeded | eTraversalNeeded; } } - std::vector> callbackHandles; - if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!filteredListeners.empty())) { - for (auto& [listener, callbackIds] : filteredListeners) { - callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface)); - } - } if (what & layer_state_t::eBufferChanged && layer->setBuffer(s.bufferData, postTime, desiredPresentTime, isAutoTimestamp, @@ -4188,7 +4181,11 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime layer->setFrameTimelineVsyncForBufferlessTransaction(frameTimelineInfo, postTime); } - if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded; + if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!filteredListeners.empty())) { + if (layer->setTransactionCompletedListeners(filteredListeners, s.surface)) { + flags |= eTraversalNeeded; + } + } // Do not put anything that updates layer state or modifies flags after // setTransactionCompletedListener return flags; diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index f3d46ea061..418fbc5c44 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -74,10 +74,10 @@ TransactionCallbackInvoker::~TransactionCallbackInvoker() { } } -void TransactionCallbackInvoker::addEmptyTransaction(const ListenerCallbacks& listenerCallbacks) { +void TransactionCallbackInvoker::addEmptyCallback(const ListenerCallbacks& listenerCallbacks) { auto& [listener, callbackIds] = listenerCallbacks; - auto& transactionStatsDeque = mCompletedTransactions[listener]; - transactionStatsDeque.emplace_back(callbackIds); + TransactionStats* transactionStats; + findOrCreateTransactionStats(listener, callbackIds, &transactionStats); } status_t TransactionCallbackInvoker::addOnCommitCallbackHandles( @@ -116,7 +116,7 @@ status_t TransactionCallbackInvoker::addCallbackHandles( return NO_ERROR; } -status_t TransactionCallbackInvoker::registerUnpresentedCallbackHandle( +status_t TransactionCallbackInvoker::addUnpresentedCallbackHandle( const sp& handle) { return addCallbackHandle(handle, std::vector()); } diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index e203d41bd9..6f67947081 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -71,8 +71,10 @@ public: // Adds the Transaction CallbackHandle from a layer that does not need to be relatched and // presented this frame. - status_t registerUnpresentedCallbackHandle(const sp& handle); - void addEmptyTransaction(const ListenerCallbacks& listenerCallbacks); + status_t addUnpresentedCallbackHandle(const sp& handle); + // Adds the callback handles for empty transactions or for non-buffer layer updates which do not + // include layer stats. + void addEmptyCallback(const ListenerCallbacks& listenerCallbacks); void addPresentFence(const sp& presentFence); @@ -81,14 +83,12 @@ public: mCompletedTransactions.clear(); } - status_t addCallbackHandle(const sp& handle, - const std::vector& jankData); - - private: status_t findOrCreateTransactionStats(const sp& listener, const std::vector& callbackIds, TransactionStats** outTransactionStats); + status_t addCallbackHandle(const sp& handle, + const std::vector& jankData); std::unordered_map, std::deque, IListenerHash> mCompletedTransactions; diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp index 91a5b528f8..7beba15062 100644 --- a/services/surfaceflinger/tests/LayerCallback_test.cpp +++ b/services/surfaceflinger/tests/LayerCallback_test.cpp @@ -1067,7 +1067,7 @@ TEST_F(LayerCallbackTest, EmptyBufferStateChanges) { } // b202394221 -TEST_F(LayerCallbackTest, DISABLED_NonBufferLayerStateChanges) { +TEST_F(LayerCallbackTest, NonBufferLayerStateChanges) { sp layer; ASSERT_NO_FATAL_FAILURE(layer = createColorLayer("ColorLayer", Color::RED)); @@ -1085,4 +1085,47 @@ TEST_F(LayerCallbackTest, DISABLED_NonBufferLayerStateChanges) { EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true)); } +class TimedCallbackHelper { +public: + static void function(void* callbackContext, nsecs_t, const sp&, + const std::vector&) { + if (!callbackContext) { + ALOGE("failed to get callback context"); + } + TimedCallbackHelper* helper = static_cast(callbackContext); + std::lock_guard lock(helper->mMutex); + helper->mInvokedTime = systemTime(); + helper->mCv.notify_all(); + } + + void waitForCallback() { + std::unique_lock lock(mMutex); + ASSERT_TRUE(mCv.wait_for(lock, std::chrono::seconds(3), [&] { return mInvokedTime != -1; })) + << "did not receive callback"; + } + void* getContext() { return static_cast(this); } + + std::mutex mMutex; + std::condition_variable mCv; + nsecs_t mInvokedTime = -1; +}; + +TEST_F(LayerCallbackTest, EmptyTransactionCallbackOrder) { + TimedCallbackHelper onCommitCallback; + TimedCallbackHelper onCompleteCallback; + + // Add transaction callback before on commit callback + Transaction() + .addTransactionCompletedCallback(onCompleteCallback.function, + onCompleteCallback.getContext()) + .addTransactionCommittedCallback(onCommitCallback.function, + onCommitCallback.getContext()) + .apply(); + + EXPECT_NO_FATAL_FAILURE(onCompleteCallback.waitForCallback()); + EXPECT_NO_FATAL_FAILURE(onCommitCallback.waitForCallback()); + // verify we get the oncomplete at the same time or after the oncommit callback. + EXPECT_GE(onCompleteCallback.mInvokedTime, onCommitCallback.mInvokedTime); +} + } // namespace android -- cgit v1.2.3-59-g8ed1b From 835c4b5a116203fa5baf5e48bdbdaae5a97034b6 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 4 Nov 2021 11:46:49 -0700 Subject: SF: Increase default tracing buffer size to 20MB Memory will only be allocated if user enables tracing. Bug: 201659992 Test: go/winscope-bugreport Change-Id: I50b44497e6899dfc55fc7347124008af54558d36 --- services/surfaceflinger/SurfaceTracing.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h index cea1a3324e..97adb20c63 100644 --- a/services/surfaceflinger/SurfaceTracing.h +++ b/services/surfaceflinger/SurfaceTracing.h @@ -77,7 +77,7 @@ public: private: class Runner; - static constexpr auto DEFAULT_BUFFER_SIZE = 5_MB; + static constexpr auto DEFAULT_BUFFER_SIZE = 20_MB; static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.winscope"; SurfaceFlinger& mFlinger; -- cgit v1.2.3-59-g8ed1b From 86653e9e2caae7ee5295d36a85e1d5b098751bbc Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Wed, 3 Nov 2021 17:19:36 -0700 Subject: SF: Add autorefresh to drawingstate Autorefresh does not need to be an atomic variable. It is only accessed from the main thread. Move it to drawing state so it can be accessed from the base Layer class when creating the starting state. Test: presubmit Bug: 200284593 Change-Id: I52a00c4185a3a883e4d5cf850257bb3a098b4d22 --- services/surfaceflinger/BufferLayer.h | 3 +-- services/surfaceflinger/BufferQueueLayer.cpp | 4 ++-- services/surfaceflinger/BufferStateLayer.cpp | 4 +--- services/surfaceflinger/Layer.h | 2 ++ 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 8c4c8b7a78..a4c21f4caf 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -171,7 +171,7 @@ protected: // the mStateLock. ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0; - bool getAutoRefresh() const { return mAutoRefresh; } + bool getAutoRefresh() const { return mDrawingState.autoRefresh; } bool getSidebandStreamChanged() const { return mSidebandStreamChanged; } // Returns true if the next buffer should be presented at the expected present time @@ -182,7 +182,6 @@ protected: // specific logic virtual bool isBufferDue(nsecs_t /*expectedPresentTime*/) const = 0; - std::atomic mAutoRefresh{false}; std::atomic mSidebandStreamChanged{false}; private: diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 8aecec131f..28c387e5bd 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -216,7 +216,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t bool autoRefresh; status_t updateResult = mConsumer->updateTexImage(&r, expectedPresentTime, &autoRefresh, &queuedBuffer, maxFrameNumberToAcquire); - mAutoRefresh = autoRefresh; + mDrawingState.autoRefresh = autoRefresh; if (updateResult == BufferQueue::PRESENT_LATER) { // Producer doesn't want buffer to be displayed yet. Signal a // layer update so we check again at the next opportunity. @@ -300,7 +300,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t // Decrement the queued-frames count. Signal another event if we // have more frames pending. - if ((queuedBuffer && more_frames_pending) || mAutoRefresh) { + if ((queuedBuffer && more_frames_pending) || mDrawingState.autoRefresh) { mFlinger->onLayerUpdate(); } diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index f7f96ab1b1..4f0bbd243b 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -660,9 +660,7 @@ bool BufferStateLayer::onPreComposition(nsecs_t refreshStartTime) { } void BufferStateLayer::setAutoRefresh(bool autoRefresh) { - if (!mAutoRefresh.exchange(autoRefresh)) { - mFlinger->onLayerUpdate(); - } + mDrawingState.autoRefresh = autoRefresh; } bool BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index bf338c18ad..297ded043f 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -280,6 +280,8 @@ public: sp releaseBufferEndpoint; gui::DropInputMode dropInputMode; + + bool autoRefresh = false; }; /* -- cgit v1.2.3-59-g8ed1b From 7e1ee565b3fe4738e6771bceb2e9679562232992 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Tue, 26 Oct 2021 10:19:49 -0700 Subject: Move Joystick and Touchpad event transformation logic to MotionEvent We would like to have all source and axis based transformations calculated in the same place, which will be in the MotionEvent class. This has the added benefit that MotionEvents created by developers through MotionEvent.obtain() in Java will behave like motion events generated from input devices in terms of how they're affected by transformations. Since axes from joysticks and touchpads should never be transfomred, we previously solved this by using identity matrices for them in InputDispatcher. Now, we move that logic to MotionEvent when applying the transform. Bug: 179274888 Test: atest libinput_test Test: atest inputflinger_tests Change-Id: Ic02466e01f2ba3131aca73bd10933ff81cb38cc9 --- include/input/Input.h | 5 +- libs/input/Input.cpp | 36 +++++++++++--- libs/input/tests/InputEvent_test.cpp | 57 ++++++++++++++++------ .../inputflinger/dispatcher/InputDispatcher.cpp | 12 ----- .../inputflinger/tests/InputDispatcher_test.cpp | 53 -------------------- 5 files changed, 77 insertions(+), 86 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index 54c71140eb..7cc595a264 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -801,8 +801,11 @@ public: static std::string actionToString(int32_t action); + // MotionEvent will transform various axes in different ways, based on the source. For + // example, the x and y axes will not have any offsets/translations applied if it comes from a + // relative mouse device (since SOURCE_RELATIVE_MOUSE is a non-pointer source). These methods + // are used to apply these transformations for different axes. static vec2 calculateTransformedXY(uint32_t source, const ui::Transform&, const vec2& xy); - static float calculateTransformedAxisValue(int32_t axis, uint32_t source, const ui::Transform&, const PointerCoords&); diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index d018800c90..24a77209c4 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -66,11 +66,21 @@ vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) return transformedXy - transformedOrigin; } -bool shouldDisregardTranslation(uint32_t source) { +bool isFromSource(uint32_t source, uint32_t test) { + return (source & test) == test; +} + +bool shouldDisregardTransformation(uint32_t source) { + // Do not apply any transformations to axes from joysticks or touchpads. + return isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK) || + isFromSource(source, AINPUT_SOURCE_CLASS_POSITION); +} + +bool shouldDisregardOffset(uint32_t source) { // Pointer events are the only type of events that refer to absolute coordinates on the display, // so we should apply the entire window transform. For other types of events, we should make // sure to not apply the window translation/offset. - return (source & AINPUT_SOURCE_CLASS_POINTER) == 0; + return !isFromSource(source, AINPUT_SOURCE_CLASS_POINTER); } } // namespace @@ -707,7 +717,7 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { #endif bool MotionEvent::isTouchEvent(uint32_t source, int32_t action) { - if (source & AINPUT_SOURCE_CLASS_POINTER) { + if (isFromSource(source, AINPUT_SOURCE_CLASS_POINTER)) { // Specifically excludes HOVER_MOVE and SCROLL. switch (action & AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_DOWN: @@ -764,17 +774,31 @@ std::string MotionEvent::actionToString(int32_t action) { return android::base::StringPrintf("%" PRId32, action); } +// Apply the given transformation to the point without checking whether the entire transform +// should be disregarded altogether for the provided source. +static inline vec2 calculateTransformedXYUnchecked(uint32_t source, const ui::Transform& transform, + const vec2& xy) { + return shouldDisregardOffset(source) ? transformWithoutTranslation(transform, xy) + : transform.transform(xy); +} + vec2 MotionEvent::calculateTransformedXY(uint32_t source, const ui::Transform& transform, const vec2& xy) { - return shouldDisregardTranslation(source) ? transformWithoutTranslation(transform, xy) - : transform.transform(xy); + if (shouldDisregardTransformation(source)) { + return xy; + } + return calculateTransformedXYUnchecked(source, transform, xy); } float MotionEvent::calculateTransformedAxisValue(int32_t axis, uint32_t source, const ui::Transform& transform, const PointerCoords& coords) { + if (shouldDisregardTransformation(source)) { + return coords.getAxisValue(axis); + } + if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) { - const vec2 xy = calculateTransformedXY(source, transform, coords.getXYValue()); + const vec2 xy = calculateTransformedXYUnchecked(source, transform, coords.getXYValue()); static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); return xy[axis]; } diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index 1b594f142e..a92016ba3b 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -647,9 +647,8 @@ TEST_F(MotionEventTest, Transform) { ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001); } -MotionEvent createTouchDownEvent(float x, float y, float dx, float dy, - const ui::Transform& transform, - const ui::Transform& rawTransform) { +MotionEvent createMotionEvent(int32_t source, uint32_t action, float x, float y, float dx, float dy, + const ui::Transform& transform, const ui::Transform& rawTransform) { std::vector pointerProperties; pointerProperties.push_back(PointerProperties{/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER}); std::vector pointerCoords; @@ -660,8 +659,8 @@ MotionEvent createTouchDownEvent(float x, float y, float dx, float dy, pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, dy); nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC); MotionEvent event; - event.initialize(InputEvent::nextId(), /* deviceId */ 1, AINPUT_SOURCE_TOUCHSCREEN, - /* displayId */ 0, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, + event.initialize(InputEvent::nextId(), /* deviceId */ 1, source, + /* displayId */ 0, INVALID_HMAC, action, /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, transform, /* xPrecision */ 0, /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, @@ -670,6 +669,13 @@ MotionEvent createTouchDownEvent(float x, float y, float dx, float dy, return event; } +MotionEvent createTouchDownEvent(float x, float y, float dx, float dy, + const ui::Transform& transform, + const ui::Transform& rawTransform) { + return createMotionEvent(AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_DOWN, x, y, dx, dy, + transform, rawTransform); +} + TEST_F(MotionEventTest, ApplyTransform) { // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). ui::Transform identity; @@ -708,16 +714,39 @@ TEST_F(MotionEventTest, ApplyTransform) { changedEvent.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0), 0.001); } +TEST_F(MotionEventTest, JoystickAndTouchpadAreNotTransformed) { + constexpr static std::array kNonTransformedSources = {std::pair(AINPUT_SOURCE_TOUCHPAD, + AMOTION_EVENT_ACTION_DOWN), + std::pair(AINPUT_SOURCE_JOYSTICK, + AMOTION_EVENT_ACTION_MOVE)}; + // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). + ui::Transform transform(ui::Transform::ROT_90, 800, 400); + transform.set(transform.tx() + 20, transform.ty() + 40); + + for (const auto& [source, action] : kNonTransformedSources) { + const MotionEvent event = + createMotionEvent(source, action, 60, 100, 0, 0, transform, transform); + + // These events should not be transformed in any way. + ASSERT_EQ(60, event.getX(0)); + ASSERT_EQ(100, event.getY(0)); + ASSERT_EQ(event.getRawX(0), event.getX(0)); + ASSERT_EQ(event.getRawY(0), event.getY(0)); + } +} + TEST_F(MotionEventTest, NonPointerSourcesAreNotTranslated) { - constexpr static auto NON_POINTER_SOURCES = {AINPUT_SOURCE_TRACKBALL, - AINPUT_SOURCE_MOUSE_RELATIVE, - AINPUT_SOURCE_JOYSTICK}; - for (uint32_t source : NON_POINTER_SOURCES) { - // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). - ui::Transform transform(ui::Transform::ROT_90, 800, 400); - transform.set(transform.tx() + 20, transform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, 42, 96, transform, transform); - event.setSource(source); + constexpr static std::array kNonPointerSources = {std::pair(AINPUT_SOURCE_TRACKBALL, + AMOTION_EVENT_ACTION_DOWN), + std::pair(AINPUT_SOURCE_MOUSE_RELATIVE, + AMOTION_EVENT_ACTION_MOVE)}; + // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). + ui::Transform transform(ui::Transform::ROT_90, 800, 400); + transform.set(transform.tx() + 20, transform.ty() + 40); + + for (const auto& [source, action] : kNonPointerSources) { + const MotionEvent event = + createMotionEvent(source, action, 60, 100, 42, 96, transform, transform); // Since this event comes from a non-pointer source, it should include rotation but not // translation/offset. diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 176cf8943a..1b19311b2f 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -342,18 +342,6 @@ bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry) { std::unique_ptr createDispatchEntry(const InputTarget& inputTarget, std::shared_ptr eventEntry, int32_t inputTargetFlags) { - if (eventEntry->type == EventEntry::Type::MOTION) { - const MotionEntry& motionEntry = static_cast(*eventEntry); - if ((motionEntry.source & AINPUT_SOURCE_CLASS_JOYSTICK) || - (motionEntry.source & AINPUT_SOURCE_CLASS_POSITION)) { - const ui::Transform identityTransform; - // Use identity transform for joystick and position-based (touchpad) events because they - // don't depend on the window transform. - return std::make_unique(eventEntry, inputTargetFlags, identityTransform, - identityTransform, 1.0f /*globalScaleFactor*/); - } - } - if (inputTarget.useDefaultPointerTransform()) { const ui::Transform& transform = inputTarget.getDefaultPointerTransform(); return std::make_unique(eventEntry, inputTargetFlags, transform, diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index ba0ce95458..d8fd16c5e6 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -3012,59 +3012,6 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState); } -TEST_F(InputDispatcherTest, NonPointerMotionEvent_JoystickAndTouchpadNotTransformed) { - std::shared_ptr application = std::make_shared(); - sp window = - new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); - const std::string name = window->getName(); - - // Window gets transformed by offset values. - window->setWindowOffset(500.0f, 500.0f); - - mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); - window->setFocusable(true); - - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); - - // First, we set focused window so that focusedWindowHandle is not null. - setFocusedWindow(window); - - // Second, we consume focus event if it is right or wrong according to onFocusChangedLocked. - window->consumeFocusEvent(true); - - constexpr const std::array nonTransformedSources = {std::pair(AINPUT_SOURCE_TOUCHPAD, - AMOTION_EVENT_ACTION_DOWN), - std::pair(AINPUT_SOURCE_JOYSTICK, - AMOTION_EVENT_ACTION_MOVE)}; - for (const auto& [source, action] : nonTransformedSources) { - const NotifyMotionArgs motionArgs = generateMotionArgs(action, source, ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&motionArgs); - - MotionEvent* event = window->consumeMotion(); - ASSERT_NE(event, nullptr); - - const MotionEvent& motionEvent = *event; - EXPECT_EQ(action, motionEvent.getAction()); - EXPECT_EQ(motionArgs.pointerCount, motionEvent.getPointerCount()); - - float expectedX = motionArgs.pointerCoords[0].getX(); - float expectedY = motionArgs.pointerCoords[0].getY(); - - // Ensure the axis values from the final motion event are not transformed. - EXPECT_EQ(expectedX, motionEvent.getX(0)) - << "expected " << expectedX << " for x coord of " << name.c_str() << ", got " - << motionEvent.getX(0); - EXPECT_EQ(expectedY, motionEvent.getY(0)) - << "expected " << expectedY << " for y coord of " << name.c_str() << ", got " - << motionEvent.getY(0); - // Ensure the raw and transformed axis values for the motion event are the same. - EXPECT_EQ(motionEvent.getRawX(0), motionEvent.getX(0)) - << "expected raw and transformed X-axis values to be equal"; - EXPECT_EQ(motionEvent.getRawY(0), motionEvent.getY(0)) - << "expected raw and transformed Y-axis values to be equal"; - } -} - /** * Ensure that separate calls to sign the same data are generating the same key. * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance -- cgit v1.2.3-59-g8ed1b From 8b89c2f2e6576c29fcef8b207a1dbb0a7d9d8362 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 29 Jul 2021 16:30:14 +0000 Subject: Clean up after enabling per-window-input-rotation The input feature of per-window-input-rotation is now enabled by default. Since we don't want to maintain two pipelines for input rotation, we remove the old code path and clean up accordingly. Bug: 188939842 Test: presubmit Test: manual, test that touch and mouse works with display rotated Change-Id: I0478bb4933c739b2975cbd170cc5dfdaeea0fd57 --- services/inputflinger/Android.bp | 3 +- services/inputflinger/dispatcher/Android.bp | 1 - .../inputflinger/dispatcher/InputDispatcher.cpp | 41 ++++----- services/inputflinger/reader/Android.bp | 5 +- .../reader/mapper/CursorInputMapper.cpp | 56 +++++-------- .../reader/mapper/TouchCursorInputMapperCommon.h | 8 -- .../reader/mapper/TouchInputMapper.cpp | 97 ++++++++-------------- services/inputflinger/sysprop/Android.bp | 15 ---- .../sysprop/InputFlingerProperties.sysprop | 27 ------ services/inputflinger/tests/InputReader_test.cpp | 10 --- services/surfaceflinger/SurfaceFlinger.cpp | 34 +++----- 11 files changed, 88 insertions(+), 209 deletions(-) delete mode 100644 services/inputflinger/sysprop/Android.bp delete mode 100644 services/inputflinger/sysprop/InputFlingerProperties.sysprop diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 73e57495e6..8cdb706bcc 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -73,7 +73,6 @@ cc_defaults { "libui", "lib-platform-compat-native-api", "server_configurable_flags", - "InputFlingerProperties", ], static_libs: [ "libattestation", @@ -125,7 +124,7 @@ filegroup { "InputListener.cpp", "InputReaderBase.cpp", "InputThread.cpp", - "VibrationElement.cpp" + "VibrationElement.cpp", ], } diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp index 171f2b5ce8..4757d31d91 100644 --- a/services/inputflinger/dispatcher/Android.bp +++ b/services/inputflinger/dispatcher/Android.bp @@ -68,7 +68,6 @@ cc_defaults { "libutils", "lib-platform-compat-native-api", "server_configurable_flags", - "InputFlingerProperties", ], static_libs: [ "libattestation", diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 1b19311b2f..695258759b 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -19,7 +19,6 @@ #define LOG_NDEBUG 1 -#include #include #include #include @@ -112,15 +111,6 @@ private: std::mutex& mMutex; }; -// When per-window-input-rotation is enabled, InputFlinger works in the un-rotated display -// coordinates and SurfaceFlinger includes the display rotation in the input window transforms. -bool isPerWindowInputRotationEnabled() { - static const bool PER_WINDOW_INPUT_ROTATION = - sysprop::InputFlingerProperties::per_window_input_rotation().value_or(true); - - return PER_WINDOW_INPUT_ROTATION; -} - // Default input dispatching timeout if there is no focused application or paused window // from which to determine an appropriate dispatching timeout. const std::chrono::duration DEFAULT_INPUT_DISPATCHING_TIMEOUT = std::chrono::milliseconds( @@ -2519,8 +2509,7 @@ void InputDispatcher::addWindowTargetLocked(const sp& windowHa if (displayInfoIt != mDisplayInfos.end()) { inputTarget.displayTransform = displayInfoIt->second.transform; } else { - ALOGI_IF(isPerWindowInputRotationEnabled(), - "DisplayInfo not found for window on display: %d", windowInfo->displayId); + ALOGE("DisplayInfo not found for window on display: %d", windowInfo->displayId); } inputTargets.push_back(inputTarget); it = inputTargets.end() - 1; @@ -4725,21 +4714,19 @@ void InputDispatcher::setInputWindowsLocked( } } - if (isPerWindowInputRotationEnabled()) { - // Determine if the orientation of any of the input windows have changed, and cancel all - // pointer events if necessary. - for (const sp& oldWindowHandle : oldWindowHandles) { - const sp newWindowHandle = getWindowHandleLocked(oldWindowHandle); - if (newWindowHandle != nullptr && - newWindowHandle->getInfo()->transform.getOrientation() != - oldWindowOrientations[oldWindowHandle->getId()]) { - std::shared_ptr inputChannel = - getInputChannelLocked(newWindowHandle->getToken()); - if (inputChannel != nullptr) { - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "touched window's orientation changed"); - synthesizeCancelationEventsForInputChannelLocked(inputChannel, options); - } + // Determine if the orientation of any of the input windows have changed, and cancel all + // pointer events if necessary. + for (const sp& oldWindowHandle : oldWindowHandles) { + const sp newWindowHandle = getWindowHandleLocked(oldWindowHandle); + if (newWindowHandle != nullptr && + newWindowHandle->getInfo()->transform.getOrientation() != + oldWindowOrientations[oldWindowHandle->getId()]) { + std::shared_ptr inputChannel = + getInputChannelLocked(newWindowHandle->getToken()); + if (inputChannel != nullptr) { + CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, + "touched window's orientation changed"); + synthesizeCancelationEventsForInputChannelLocked(inputChannel, options); } } } diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp index ee7b392bcd..51546ce983 100644 --- a/services/inputflinger/reader/Android.bp +++ b/services/inputflinger/reader/Android.bp @@ -71,7 +71,6 @@ cc_defaults { "libstatslog", "libui", "libutils", - "InputFlingerProperties", ], static_libs: [ "libc++fs", @@ -86,7 +85,7 @@ cc_library_shared { name: "libinputreader", defaults: [ "inputflinger_defaults", - "libinputreader_defaults" + "libinputreader_defaults", ], srcs: [ "InputReaderFactory.cpp", @@ -100,6 +99,6 @@ cc_library_shared { "libinputreader_headers", ], static_libs: [ - "libc++fs" + "libc++fs", ], } diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index f3d7cdc48b..15ba45945a 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -193,28 +193,18 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* const bool isOrientedDevice = (mParameters.orientationAware && mParameters.hasAssociatedDisplay); - if (isPerWindowInputRotationEnabled()) { - // When per-window input rotation is enabled, InputReader works in the un-rotated - // coordinate space, so we don't need to do anything if the device is already - // orientation-aware. If the device is not orientation-aware, then we need to apply the - // inverse rotation of the display so that when the display rotation is applied later - // as a part of the per-window transform, we get the expected screen coordinates. - if (!isOrientedDevice) { - std::optional internalViewport = - config->getDisplayViewportByType(ViewportType::INTERNAL); - if (internalViewport) { - mOrientation = getInverseRotation(internalViewport->orientation); - mDisplayWidth = internalViewport->deviceWidth; - mDisplayHeight = internalViewport->deviceHeight; - } - } - } else { - if (isOrientedDevice) { - std::optional internalViewport = - config->getDisplayViewportByType(ViewportType::INTERNAL); - if (internalViewport) { - mOrientation = internalViewport->orientation; - } + // InputReader works in the un-rotated display coordinate space, so we don't need to do + // anything if the device is already orientation-aware. If the device is not + // orientation-aware, then we need to apply the inverse rotation of the display so that + // when the display rotation is applied later as a part of the per-window transform, we + // get the expected screen coordinates. + if (!isOrientedDevice) { + std::optional internalViewport = + config->getDisplayViewportByType(ViewportType::INTERNAL); + if (internalViewport) { + mOrientation = getInverseRotation(internalViewport->orientation); + mDisplayWidth = internalViewport->deviceWidth; + mDisplayHeight = internalViewport->deviceHeight; } } @@ -347,12 +337,11 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { if (moved) { float dx = deltaX; float dy = deltaY; - if (isPerWindowInputRotationEnabled()) { - // Rotate the delta from InputReader's un-rotated coordinate space to - // PointerController's rotated coordinate space that is oriented with the - // viewport. - rotateDelta(getInverseRotation(mOrientation), &dx, &dy); - } + // Rotate the delta from InputReader's un-rotated coordinate space to + // PointerController's rotated coordinate space that is oriented with the + // viewport. + rotateDelta(getInverseRotation(mOrientation), &dx, &dy); + mPointerController->move(dx, dy); } @@ -364,12 +353,11 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { } mPointerController->getPosition(&xCursorPosition, &yCursorPosition); - if (isPerWindowInputRotationEnabled()) { - // Rotate the cursor position that is in PointerController's rotated coordinate space - // to InputReader's un-rotated coordinate space. - rotatePoint(mOrientation, xCursorPosition /*byRef*/, yCursorPosition /*byRef*/, - mDisplayWidth, mDisplayHeight); - } + // Rotate the cursor position that is in PointerController's rotated coordinate space + // to InputReader's un-rotated coordinate space. + rotatePoint(mOrientation, xCursorPosition /*byRef*/, yCursorPosition /*byRef*/, + mDisplayWidth, mDisplayHeight); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX); diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h index 197be98172..8c30e38908 100644 --- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h +++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h @@ -17,7 +17,6 @@ #ifndef _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H #define _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H -#include #include #include @@ -29,13 +28,6 @@ namespace android { // --- Static Definitions --- -// When per-window input rotation is enabled, display transformations such as rotation and -// projection are part of the input window's transform. This means InputReader should work in the -// un-rotated coordinate space. -static bool isPerWindowInputRotationEnabled() { - return sysprop::InputFlingerProperties::per_window_input_rotation().value_or(true); -} - static int32_t getInverseRotation(int32_t orientation) { switch (orientation) { case DISPLAY_ORIENTATION_90: diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index fd33df9347..57f522539b 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -749,43 +749,31 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { mPhysicalLeft = naturalPhysicalLeft; mPhysicalTop = naturalPhysicalTop; - if (isPerWindowInputRotationEnabled()) { - // When per-window input rotation is enabled, InputReader works in the display - // space, so the surface bounds are the bounds of the display device. - const int32_t oldSurfaceWidth = mRawSurfaceWidth; - const int32_t oldSurfaceHeight = mRawSurfaceHeight; - mRawSurfaceWidth = naturalDeviceWidth; - mRawSurfaceHeight = naturalDeviceHeight; - mSurfaceLeft = 0; - mSurfaceTop = 0; - mSurfaceRight = mRawSurfaceWidth; - mSurfaceBottom = mRawSurfaceHeight; - // When per-window input rotation is enabled, InputReader works in the un-rotated - // coordinate space, so we don't need to do anything if the device is already - // orientation-aware. If the device is not orientation-aware, then we need to apply - // the inverse rotation of the display so that when the display rotation is applied - // later as a part of the per-window transform, we get the expected screen - // coordinates. - mSurfaceOrientation = mParameters.orientationAware - ? DISPLAY_ORIENTATION_0 - : getInverseRotation(mViewport.orientation); - // For orientation-aware devices that work in the un-rotated coordinate space, the - // viewport update should be skipped if it is only a change in the orientation. - skipViewportUpdate = mParameters.orientationAware && - mRawSurfaceWidth == oldSurfaceWidth && - mRawSurfaceHeight == oldSurfaceHeight && viewportOrientationChanged; - } else { - mRawSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth; - mRawSurfaceHeight = - naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight; - mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth; - mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight; - mSurfaceRight = mSurfaceLeft + naturalLogicalWidth; - mSurfaceBottom = mSurfaceTop + naturalLogicalHeight; - - mSurfaceOrientation = mParameters.orientationAware ? mViewport.orientation - : DISPLAY_ORIENTATION_0; - } + // TODO(prabirmsp): Cleanup surface bounds. + // When per-window input rotation is enabled, InputReader works in the display + // space, so the surface bounds are the bounds of the display device. + const int32_t oldSurfaceWidth = mRawSurfaceWidth; + const int32_t oldSurfaceHeight = mRawSurfaceHeight; + mRawSurfaceWidth = naturalDeviceWidth; + mRawSurfaceHeight = naturalDeviceHeight; + mSurfaceLeft = 0; + mSurfaceTop = 0; + mSurfaceRight = mRawSurfaceWidth; + mSurfaceBottom = mRawSurfaceHeight; + + // InputReader works in the un-rotated display coordinate space, so we don't need to do + // anything if the device is already orientation-aware. If the device is not + // orientation-aware, then we need to apply the inverse rotation of the display so that + // when the display rotation is applied later as a part of the per-window transform, we + // get the expected screen coordinates. + mSurfaceOrientation = mParameters.orientationAware + ? DISPLAY_ORIENTATION_0 + : getInverseRotation(mViewport.orientation); + // For orientation-aware devices that work in the un-rotated coordinate space, the + // viewport update should be skipped if it is only a change in the orientation. + skipViewportUpdate = mParameters.orientationAware && + mRawSurfaceWidth == oldSurfaceWidth && mRawSurfaceHeight == oldSurfaceHeight && + viewportOrientationChanged; // Apply the input device orientation for the device. mSurfaceOrientation = @@ -3781,16 +3769,10 @@ bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) { const float xScaled = (x - mRawPointerAxes.x.minValue) * mXScale; const float yScaled = (y - mRawPointerAxes.y.minValue) * mYScale; - if (isPerWindowInputRotationEnabled()) { - return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue && - xScaled >= mPhysicalLeft && xScaled <= (mPhysicalLeft + mPhysicalWidth) && - y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue && - yScaled >= mPhysicalTop && yScaled <= (mPhysicalTop + mPhysicalHeight); - } return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue && - xScaled >= mSurfaceLeft && xScaled <= mSurfaceRight && + xScaled >= mPhysicalLeft && xScaled <= (mPhysicalLeft + mPhysicalWidth) && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue && - yScaled >= mSurfaceTop && yScaled <= mSurfaceBottom; + yScaled >= mPhysicalTop && yScaled <= (mPhysicalTop + mPhysicalHeight); } const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(int32_t x, int32_t y) { @@ -4048,11 +4030,9 @@ std::optional TouchInputMapper::getAssociatedDisplayId() { } void TouchInputMapper::moveMouseCursor(float dx, float dy) const { - if (isPerWindowInputRotationEnabled()) { - // Convert from InputReader's un-rotated coordinate space to PointerController's coordinate - // space that is oriented with the viewport. - rotateDelta(mViewport.orientation, &dx, &dy); - } + // Convert from InputReader's un-rotated coordinate space to PointerController's coordinate + // space that is oriented with the viewport. + rotateDelta(mViewport.orientation, &dx, &dy); mPointerController->move(dx, dy); } @@ -4062,7 +4042,6 @@ std::pair TouchInputMapper::getMouseCursorPosition() const { float y = 0; mPointerController->getPosition(&x, &y); - if (!isPerWindowInputRotationEnabled()) return {x, y}; if (!mViewport.isValid()) return {x, y}; // Convert from PointerController's rotated coordinate space that is oriented with the viewport @@ -4073,11 +4052,9 @@ std::pair TouchInputMapper::getMouseCursorPosition() const { } void TouchInputMapper::setMouseCursorPosition(float x, float y) const { - if (isPerWindowInputRotationEnabled() && mViewport.isValid()) { - // Convert from InputReader's un-rotated coordinate space to PointerController's rotated - // coordinate space that is oriented with the viewport. - rotatePoint(mViewport.orientation, x, y, mRawSurfaceWidth, mRawSurfaceHeight); - } + // Convert from InputReader's un-rotated coordinate space to PointerController's rotated + // coordinate space that is oriented with the viewport. + rotatePoint(mViewport.orientation, x, y, mRawSurfaceWidth, mRawSurfaceHeight); mPointerController->setPosition(x, y); } @@ -4092,11 +4069,9 @@ void TouchInputMapper::setTouchSpots(const PointerCoords* spotCoords, const uint float y = spotCoords[index].getY(); float pressure = spotCoords[index].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); - if (isPerWindowInputRotationEnabled()) { - // Convert from InputReader's un-rotated coordinate space to PointerController's rotated - // coordinate space. - rotatePoint(mViewport.orientation, x, y, mRawSurfaceWidth, mRawSurfaceHeight); - } + // Convert from InputReader's un-rotated coordinate space to PointerController's rotated + // coordinate space. + rotatePoint(mViewport.orientation, x, y, mRawSurfaceWidth, mRawSurfaceHeight); outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_X, x); outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_Y, y); diff --git a/services/inputflinger/sysprop/Android.bp b/services/inputflinger/sysprop/Android.bp deleted file mode 100644 index b9d65ee246..0000000000 --- a/services/inputflinger/sysprop/Android.bp +++ /dev/null @@ -1,15 +0,0 @@ -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_native_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_native_license"], -} - -sysprop_library { - name: "InputFlingerProperties", - srcs: ["*.sysprop"], - api_packages: ["android.sysprop"], - property_owner: "Platform", -} diff --git a/services/inputflinger/sysprop/InputFlingerProperties.sysprop b/services/inputflinger/sysprop/InputFlingerProperties.sysprop deleted file mode 100644 index 1c7e724332..0000000000 --- a/services/inputflinger/sysprop/InputFlingerProperties.sysprop +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (C) 2021 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the License); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an AS IS BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -module: "android.sysprop.InputFlingerProperties" -owner: Platform - -# When per-window-input-rotation is enabled, InputReader works in the un-rotated -# display coordinate space, and the display rotation is encoded as part of the -# input window transform that is sent from SurfaceFlinger to InputDispatcher. -prop { - api_name: "per_window_input_rotation" - type: Boolean - scope: Internal - access: ReadWrite - prop_name: "persist.debug.per_window_input_rotation" -} diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 53b03ada3a..336afc67fc 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -16,7 +16,6 @@ #include #include -#include #include #include #include @@ -2695,7 +2694,6 @@ protected: static const int32_t DEVICE_CONTROLLER_NUMBER; static const Flags DEVICE_CLASSES; static const int32_t EVENTHUB_ID; - static const std::optional INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE; std::shared_ptr mFakeEventHub; sp mFakePolicy; @@ -2713,18 +2711,12 @@ protected: } void SetUp() override { - // Ensure per_window_input_rotation is enabled. - sysprop::InputFlingerProperties::per_window_input_rotation(true); - SetUp(DEVICE_CLASSES); } void TearDown() override { mFakeListener.reset(); mFakePolicy.clear(); - - sysprop::InputFlingerProperties::per_window_input_rotation( - INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE); } void addConfigurationProperty(const char* key, const char* value) { @@ -2836,8 +2828,6 @@ const int32_t InputMapperTest::DEVICE_CONTROLLER_NUMBER = 0; const Flags InputMapperTest::DEVICE_CLASSES = Flags(0); // not needed for current tests const int32_t InputMapperTest::EVENTHUB_ID = 1; -const std::optional InputMapperTest::INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE = - sysprop::InputFlingerProperties::per_window_input_rotation(); // --- SwitchInputMapperTest --- diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c2dcd70166..4770feb6b1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3041,32 +3041,24 @@ void SurfaceFlinger::updateInputFlinger() { mInputWindowCommands.clear(); } -bool enablePerWindowInputRotation() { - static bool value = - android::base::GetBoolProperty("persist.debug.per_window_input_rotation", true); - return value; -} - void SurfaceFlinger::notifyWindowInfos() { std::vector windowInfos; std::vector displayInfos; std::unordered_map displayTransforms; - if (enablePerWindowInputRotation()) { - for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { - if (!display->receivesInput()) { - continue; - } - const uint32_t layerStackId = display->getLayerStack().id; - const auto& [info, transform] = display->getInputInfo(); - const auto& [it, emplaced] = displayTransforms.try_emplace(layerStackId, transform); - if (!emplaced) { - ALOGE("Multiple displays claim to accept input for the same layer stack: %u", - layerStackId); - continue; - } - displayInfos.emplace_back(info); + for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { + if (!display->receivesInput()) { + continue; + } + const uint32_t layerStackId = display->getLayerStack().id; + const auto& [info, transform] = display->getInputInfo(); + const auto& [it, emplaced] = displayTransforms.try_emplace(layerStackId, transform); + if (!emplaced) { + ALOGE("Multiple displays claim to accept input for the same layer stack: %u", + layerStackId); + continue; } + displayInfos.emplace_back(info); } mDrawingState.traverseInReverseZOrder([&](Layer* layer) { @@ -3075,7 +3067,7 @@ void SurfaceFlinger::notifyWindowInfos() { const DisplayDevice* display = ON_MAIN_THREAD(getDisplayWithInputByLayer(layer)).get(); ui::Transform displayTransform = ui::Transform(); - if (enablePerWindowInputRotation() && display != nullptr) { + if (display != nullptr) { // When calculating the screen bounds we ignore the transparent region since it may // result in an unwanted offset. const auto it = displayTransforms.find(display->getLayerStack().id); -- cgit v1.2.3-59-g8ed1b From 1728b21151df967bfe1cd7178996960ae9456236 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Tue, 19 Oct 2021 16:00:03 -0700 Subject: TouchInputMapper: Remove the concept of "surface" Prior to switching the input pipeline to work in display space, TouchInputMapper used the concept of "surface coordinates" to refer to the post-transformed logical display coordinate space. Information about the logical display was obtained from the DisplayViewport. Now that transformation to various coordinate spaces are handled within MotionEvent through various ui::Transforms, we can retire the use of logical display space from TouchInputMapper. Bug: 188939842 Test: presubmit Change-Id: I850acd07ac9aa0bbd344d8946b57204261c30e8b --- .../reader/mapper/TouchInputMapper.cpp | 222 +++++++++------------ .../inputflinger/reader/mapper/TouchInputMapper.h | 40 ++-- 2 files changed, 110 insertions(+), 152 deletions(-) diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 57f522539b..3fe6fd130f 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -168,17 +168,13 @@ TouchInputMapper::TouchInputMapper(InputDeviceContext& deviceContext) : InputMapper(deviceContext), mSource(0), mDeviceMode(DeviceMode::DISABLED), - mRawSurfaceWidth(-1), - mRawSurfaceHeight(-1), - mSurfaceLeft(0), - mSurfaceTop(0), - mSurfaceRight(0), - mSurfaceBottom(0), + mDisplayWidth(-1), + mDisplayHeight(-1), mPhysicalWidth(-1), mPhysicalHeight(-1), mPhysicalLeft(0), mPhysicalTop(0), - mSurfaceOrientation(DISPLAY_ORIENTATION_0) {} + mInputDeviceOrientation(DISPLAY_ORIENTATION_0) {} TouchInputMapper::~TouchInputMapper() {} @@ -266,11 +262,9 @@ void TouchInputMapper::dump(std::string& dump) { dumpRawPointerAxes(dump); dumpCalibration(dump); dumpAffineTransformation(dump); - dumpSurface(dump); + dumpDisplay(dump); dump += StringPrintf(INDENT3 "Translation and Scaling Factors:\n"); - dump += StringPrintf(INDENT4 "XTranslate: %0.3f\n", mXTranslate); - dump += StringPrintf(INDENT4 "YTranslate: %0.3f\n", mYTranslate); dump += StringPrintf(INDENT4 "XScale: %0.3f\n", mXScale); dump += StringPrintf(INDENT4 "YScale: %0.3f\n", mYScale); dump += StringPrintf(INDENT4 "XPrecision: %0.3f\n", mXPrecision); @@ -390,9 +384,9 @@ void TouchInputMapper::configure(nsecs_t when, const InputReaderConfiguration* c InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT | InputReaderConfiguration::CHANGE_SHOW_TOUCHES | InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) { - // Configure device sources, surface dimensions, orientation and + // Configure device sources, display dimensions, orientation and // scaling factors. - configureSurface(when, &resetNeeded); + configureInputDevice(when, &resetNeeded); } if (changes && resetNeeded) { @@ -615,7 +609,7 @@ std::optional TouchInputMapper::findViewport() { return std::make_optional(newViewport); } -void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { +void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) { DeviceMode oldDeviceMode = mDeviceMode; resolveExternalStylusPresence(); @@ -673,31 +667,28 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { } // Raw width and height in the natural orientation. - int32_t rawWidth = mRawPointerAxes.getRawWidth(); - int32_t rawHeight = mRawPointerAxes.getRawHeight(); + const int32_t rawWidth = mRawPointerAxes.getRawWidth(); + const int32_t rawHeight = mRawPointerAxes.getRawHeight(); - bool viewportChanged = mViewport != *newViewport; + const bool viewportChanged = mViewport != *newViewport; bool skipViewportUpdate = false; if (viewportChanged) { - bool viewportOrientationChanged = mViewport.orientation != newViewport->orientation; + const bool viewportOrientationChanged = mViewport.orientation != newViewport->orientation; mViewport = *newViewport; if (mDeviceMode == DeviceMode::DIRECT || mDeviceMode == DeviceMode::POINTER) { - // Convert rotated viewport to natural surface coordinates. - int32_t naturalLogicalWidth, naturalLogicalHeight; + // Convert rotated viewport to the natural orientation. int32_t naturalPhysicalWidth, naturalPhysicalHeight; int32_t naturalPhysicalLeft, naturalPhysicalTop; int32_t naturalDeviceWidth, naturalDeviceHeight; - // Apply the inverse of the input device orientation so that the surface is configured - // in the same orientation as the device. The input device orientation will be - // re-applied to mSurfaceOrientation. - const int32_t naturalSurfaceOrientation = + // Apply the inverse of the input device orientation so that the input device is + // configured in the same orientation as the viewport. The input device orientation will + // be re-applied by mInputDeviceOrientation. + const int32_t naturalDeviceOrientation = (mViewport.orientation - static_cast(mParameters.orientation) + 4) % 4; - switch (naturalSurfaceOrientation) { + switch (naturalDeviceOrientation) { case DISPLAY_ORIENTATION_90: - naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; - naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom; @@ -706,8 +697,6 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { naturalDeviceHeight = mViewport.deviceWidth; break; case DISPLAY_ORIENTATION_180: - naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft; - naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop; naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; naturalPhysicalLeft = mViewport.deviceWidth - mViewport.physicalRight; @@ -716,8 +705,6 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { naturalDeviceHeight = mViewport.deviceHeight; break; case DISPLAY_ORIENTATION_270: - naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; - naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; naturalPhysicalLeft = mViewport.physicalTop; @@ -727,8 +714,6 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { break; case DISPLAY_ORIENTATION_0: default: - naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft; - naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop; naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; naturalPhysicalLeft = mViewport.physicalLeft; @@ -749,46 +734,36 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { mPhysicalLeft = naturalPhysicalLeft; mPhysicalTop = naturalPhysicalTop; - // TODO(prabirmsp): Cleanup surface bounds. - // When per-window input rotation is enabled, InputReader works in the display - // space, so the surface bounds are the bounds of the display device. - const int32_t oldSurfaceWidth = mRawSurfaceWidth; - const int32_t oldSurfaceHeight = mRawSurfaceHeight; - mRawSurfaceWidth = naturalDeviceWidth; - mRawSurfaceHeight = naturalDeviceHeight; - mSurfaceLeft = 0; - mSurfaceTop = 0; - mSurfaceRight = mRawSurfaceWidth; - mSurfaceBottom = mRawSurfaceHeight; + const int32_t oldDisplayWidth = mDisplayWidth; + const int32_t oldDisplayHeight = mDisplayHeight; + mDisplayWidth = naturalDeviceWidth; + mDisplayHeight = naturalDeviceHeight; // InputReader works in the un-rotated display coordinate space, so we don't need to do // anything if the device is already orientation-aware. If the device is not // orientation-aware, then we need to apply the inverse rotation of the display so that // when the display rotation is applied later as a part of the per-window transform, we // get the expected screen coordinates. - mSurfaceOrientation = mParameters.orientationAware + mInputDeviceOrientation = mParameters.orientationAware ? DISPLAY_ORIENTATION_0 : getInverseRotation(mViewport.orientation); // For orientation-aware devices that work in the un-rotated coordinate space, the // viewport update should be skipped if it is only a change in the orientation. - skipViewportUpdate = mParameters.orientationAware && - mRawSurfaceWidth == oldSurfaceWidth && mRawSurfaceHeight == oldSurfaceHeight && - viewportOrientationChanged; + skipViewportUpdate = mParameters.orientationAware && mDisplayWidth == oldDisplayWidth && + mDisplayHeight == oldDisplayHeight && viewportOrientationChanged; // Apply the input device orientation for the device. - mSurfaceOrientation = - (mSurfaceOrientation + static_cast(mParameters.orientation)) % 4; + mInputDeviceOrientation = + (mInputDeviceOrientation + static_cast(mParameters.orientation)) % 4; } else { mPhysicalWidth = rawWidth; mPhysicalHeight = rawHeight; mPhysicalLeft = 0; mPhysicalTop = 0; - mRawSurfaceWidth = rawWidth; - mRawSurfaceHeight = rawHeight; - mSurfaceLeft = 0; - mSurfaceTop = 0; - mSurfaceOrientation = DISPLAY_ORIENTATION_0; + mDisplayWidth = rawWidth; + mDisplayHeight = rawHeight; + mInputDeviceOrientation = DISPLAY_ORIENTATION_0; } } @@ -817,14 +792,12 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { if ((viewportChanged && !skipViewportUpdate) || deviceModeChanged) { ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, " "display id %d", - getDeviceId(), getDeviceName().c_str(), mRawSurfaceWidth, mRawSurfaceHeight, - mSurfaceOrientation, mDeviceMode, mViewport.displayId); + getDeviceId(), getDeviceName().c_str(), mDisplayWidth, mDisplayHeight, + mInputDeviceOrientation, mDeviceMode, mViewport.displayId); // Configure X and Y factors. - mXScale = float(mRawSurfaceWidth) / rawWidth; - mYScale = float(mRawSurfaceHeight) / rawHeight; - mXTranslate = -mSurfaceLeft; - mYTranslate = -mSurfaceTop; + mXScale = float(mDisplayWidth) / rawWidth; + mYScale = float(mDisplayHeight) / rawHeight; mXPrecision = 1.0f / mXScale; mYPrecision = 1.0f / mYScale; @@ -841,7 +814,7 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { mGeometricScale = avg(mXScale, mYScale); // Size of diagonal axis. - float diagonalSize = hypotf(mRawSurfaceWidth, mRawSurfaceHeight); + float diagonalSize = hypotf(mDisplayWidth, mDisplayHeight); // Size factors. if (mCalibration.sizeCalibration != Calibration::SizeCalibration::NONE) { @@ -1003,21 +976,21 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { // Compute oriented precision, scales and ranges. // Note that the maximum value reported is an inclusive maximum value so it is one - // unit less than the total width or height of surface. - switch (mSurfaceOrientation) { + // unit less than the total width or height of the display. + switch (mInputDeviceOrientation) { case DISPLAY_ORIENTATION_90: case DISPLAY_ORIENTATION_270: mOrientedXPrecision = mYPrecision; mOrientedYPrecision = mXPrecision; - mOrientedRanges.x.min = mYTranslate; - mOrientedRanges.x.max = mRawSurfaceHeight + mYTranslate - 1; + mOrientedRanges.x.min = 0; + mOrientedRanges.x.max = mDisplayHeight - 1; mOrientedRanges.x.flat = 0; mOrientedRanges.x.fuzz = 0; mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale; - mOrientedRanges.y.min = mXTranslate; - mOrientedRanges.y.max = mRawSurfaceWidth + mXTranslate - 1; + mOrientedRanges.y.min = 0; + mOrientedRanges.y.max = mDisplayWidth - 1; mOrientedRanges.y.flat = 0; mOrientedRanges.y.fuzz = 0; mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale; @@ -1027,14 +1000,14 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { mOrientedXPrecision = mXPrecision; mOrientedYPrecision = mYPrecision; - mOrientedRanges.x.min = mXTranslate; - mOrientedRanges.x.max = mRawSurfaceWidth + mXTranslate - 1; + mOrientedRanges.x.min = 0; + mOrientedRanges.x.max = mDisplayWidth - 1; mOrientedRanges.x.flat = 0; mOrientedRanges.x.fuzz = 0; mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale; - mOrientedRanges.y.min = mYTranslate; - mOrientedRanges.y.max = mRawSurfaceHeight + mYTranslate - 1; + mOrientedRanges.y.min = 0; + mOrientedRanges.y.max = mDisplayHeight - 1; mOrientedRanges.y.flat = 0; mOrientedRanges.y.fuzz = 0; mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale; @@ -1047,7 +1020,7 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { if (mDeviceMode == DeviceMode::POINTER) { // Compute pointer gesture detection parameters. float rawDiagonal = hypotf(rawWidth, rawHeight); - float displayDiagonal = hypotf(mRawSurfaceWidth, mRawSurfaceHeight); + float displayDiagonal = hypotf(mDisplayWidth, mDisplayHeight); // Scale movements such that one whole swipe of the touch pad covers a // given area relative to the diagonal size of the display when no acceleration @@ -1081,19 +1054,15 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { } } -void TouchInputMapper::dumpSurface(std::string& dump) { +void TouchInputMapper::dumpDisplay(std::string& dump) { dump += StringPrintf(INDENT3 "%s\n", mViewport.toString().c_str()); - dump += StringPrintf(INDENT3 "RawSurfaceWidth: %dpx\n", mRawSurfaceWidth); - dump += StringPrintf(INDENT3 "RawSurfaceHeight: %dpx\n", mRawSurfaceHeight); - dump += StringPrintf(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft); - dump += StringPrintf(INDENT3 "SurfaceTop: %d\n", mSurfaceTop); - dump += StringPrintf(INDENT3 "SurfaceRight: %d\n", mSurfaceRight); - dump += StringPrintf(INDENT3 "SurfaceBottom: %d\n", mSurfaceBottom); + dump += StringPrintf(INDENT3 "DisplayWidth: %dpx\n", mDisplayWidth); + dump += StringPrintf(INDENT3 "DisplayHeight: %dpx\n", mDisplayHeight); dump += StringPrintf(INDENT3 "PhysicalWidth: %dpx\n", mPhysicalWidth); dump += StringPrintf(INDENT3 "PhysicalHeight: %dpx\n", mPhysicalHeight); dump += StringPrintf(INDENT3 "PhysicalLeft: %d\n", mPhysicalLeft); dump += StringPrintf(INDENT3 "PhysicalTop: %d\n", mPhysicalTop); - dump += StringPrintf(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation); + dump += StringPrintf(INDENT3 "InputDeviceOrientation: %d\n", mInputDeviceOrientation); } void TouchInputMapper::configureVirtualKeys() { @@ -1132,16 +1101,16 @@ void TouchInputMapper::configureVirtualKeys() { int32_t halfHeight = virtualKeyDefinition.height / 2; virtualKey.hitLeft = - (virtualKeyDefinition.centerX - halfWidth) * touchScreenWidth / mRawSurfaceWidth + + (virtualKeyDefinition.centerX - halfWidth) * touchScreenWidth / mDisplayWidth + touchScreenLeft; virtualKey.hitRight = - (virtualKeyDefinition.centerX + halfWidth) * touchScreenWidth / mRawSurfaceWidth + + (virtualKeyDefinition.centerX + halfWidth) * touchScreenWidth / mDisplayWidth + touchScreenLeft; - virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight) * touchScreenHeight / - mRawSurfaceHeight + + virtualKey.hitTop = + (virtualKeyDefinition.centerY - halfHeight) * touchScreenHeight / mDisplayHeight + touchScreenTop; - virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight / - mRawSurfaceHeight + + virtualKey.hitBottom = + (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight / mDisplayHeight + touchScreenTop; mVirtualKeys.push_back(virtualKey); } @@ -1407,7 +1376,7 @@ void TouchInputMapper::dumpAffineTransformation(std::string& dump) { void TouchInputMapper::updateAffineTransformation() { mAffineTransform = getPolicy()->getTouchAffineTransformation(getDeviceContext().getDescriptor(), - mSurfaceOrientation); + mInputDeviceOrientation); } void TouchInputMapper::reset(nsecs_t when) { @@ -1855,8 +1824,10 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, nsecs_t readTime, uint32_ // Pointer just went down. Check for virtual key press or off-screen touches. uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id); - // Exclude unscaled device for inside surface checking. - if (!isPointInsideSurface(pointer.x, pointer.y) && mDeviceMode != DeviceMode::UNSCALED) { + // Skip checking whether the pointer is inside the physical frame if the device is in + // unscaled mode. + if (!isPointInsidePhysicalFrame(pointer.x, pointer.y) && + mDeviceMode != DeviceMode::UNSCALED) { // If exactly one pointer went down, check for virtual key hit. // Otherwise we will drop the entire stroke. if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) { @@ -2125,7 +2096,7 @@ void TouchInputMapper::cookPointerData() { } // Walk through the the active pointers and map device coordinates onto - // surface coordinates and adjust for display orientation. + // display coordinates and adjust for display orientation. for (uint32_t i = 0; i < currentPointerCount; i++) { const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i]; @@ -2285,15 +2256,15 @@ void TouchInputMapper::cookPointerData() { mAffineTransform.applyTo(xTransformed, yTransformed); rotateAndScale(xTransformed, yTransformed); - // Adjust X, Y, and coverage coords for surface orientation. + // Adjust X, Y, and coverage coords for input device orientation. float left, top, right, bottom; - switch (mSurfaceOrientation) { + switch (mInputDeviceOrientation) { case DISPLAY_ORIENTATION_90: - left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - right = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate; - top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate; + left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale; + right = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale; + bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale; + top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale; orientation -= M_PI_2; if (mOrientedRanges.haveOrientation && orientation < mOrientedRanges.orientation.min) { @@ -2304,8 +2275,8 @@ void TouchInputMapper::cookPointerData() { case DISPLAY_ORIENTATION_180: left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale; right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale; - bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate; - top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate; + bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale; + top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale; orientation -= M_PI; if (mOrientedRanges.haveOrientation && orientation < mOrientedRanges.orientation.min) { @@ -2316,8 +2287,8 @@ void TouchInputMapper::cookPointerData() { case DISPLAY_ORIENTATION_270: left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale; right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale; - bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; + bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale; + top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale; orientation += M_PI_2; if (mOrientedRanges.haveOrientation && orientation > mOrientedRanges.orientation.max) { @@ -2326,10 +2297,10 @@ void TouchInputMapper::cookPointerData() { } break; default: - left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; + left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale; + right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale; + bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale; + top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale; break; } @@ -2842,7 +2813,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); + rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY); mPointerVelocityControl.move(when, &deltaX, &deltaY); // Move the pointer using a relative motion. @@ -2976,7 +2947,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); + rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY); mPointerVelocityControl.move(when, &deltaX, &deltaY); // Move the pointer using a relative motion. @@ -3234,7 +3205,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi commonDeltaX *= mPointerXMovementScale; commonDeltaY *= mPointerYMovementScale; - rotateDelta(mSurfaceOrientation, &commonDeltaX, &commonDeltaY); + rotateDelta(mInputDeviceOrientation, &commonDeltaX, &commonDeltaY); mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY); mPointerGesture.referenceGestureX += commonDeltaX; @@ -3344,7 +3315,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mCurrentRawState.rawPointerData.pointerForId(touchId); float deltaX = (pointer.x - mPointerGesture.referenceTouchX) * mPointerXZoomScale; float deltaY = (pointer.y - mPointerGesture.referenceTouchY) * mPointerYZoomScale; - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); + rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY); mPointerGesture.currentGestureProperties[i].clear(); mPointerGesture.currentGestureProperties[i].id = gestureId; @@ -3460,7 +3431,7 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs_t readTime, uint mLastRawState.rawPointerData.pointers[lastIndex].y) * mPointerYMovementScale; - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); + rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY); mPointerVelocityControl.move(when, &deltaX, &deltaY); moveMouseCursor(deltaX, deltaY); @@ -3685,7 +3656,7 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, nsecs_t readTime, uint32_t p const int32_t deviceId = getDeviceId(); std::vector frames = getDeviceContext().getVideoFrames(); std::for_each(frames.begin(), frames.end(), - [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); }); + [this](TouchVideoFrame& frame) { frame.rotate(this->mInputDeviceOrientation); }); NotifyMotionArgs args(getContext()->getNextId(), when, readTime, deviceId, source, displayId, policyFlags, action, actionButton, flags, metaState, buttonState, MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties, @@ -3729,43 +3700,42 @@ void TouchInputMapper::cancelTouch(nsecs_t when, nsecs_t readTime) { abortTouches(when, readTime, 0 /* policyFlags*/); } -// Transform raw coordinate to surface coordinate -void TouchInputMapper::rotateAndScale(float& x, float& y) { - // Scale to surface coordinate. +// Transform input device coordinates to display panel coordinates. +void TouchInputMapper::rotateAndScale(float& x, float& y) const { const float xScaled = float(x - mRawPointerAxes.x.minValue) * mXScale; const float yScaled = float(y - mRawPointerAxes.y.minValue) * mYScale; const float xScaledMax = float(mRawPointerAxes.x.maxValue - x) * mXScale; const float yScaledMax = float(mRawPointerAxes.y.maxValue - y) * mYScale; - // Rotate to surface coordinate. + // Rotate to display coordinate. // 0 - no swap and reverse. // 90 - swap x/y and reverse y. // 180 - reverse x, y. // 270 - swap x/y and reverse x. - switch (mSurfaceOrientation) { + switch (mInputDeviceOrientation) { case DISPLAY_ORIENTATION_0: - x = xScaled + mXTranslate; - y = yScaled + mYTranslate; + x = xScaled; + y = yScaled; break; case DISPLAY_ORIENTATION_90: - y = xScaledMax - (mRawSurfaceWidth - mSurfaceRight); - x = yScaled + mYTranslate; + y = xScaledMax; + x = yScaled; break; case DISPLAY_ORIENTATION_180: - x = xScaledMax - (mRawSurfaceWidth - mSurfaceRight); - y = yScaledMax - (mRawSurfaceHeight - mSurfaceBottom); + x = xScaledMax; + y = yScaledMax; break; case DISPLAY_ORIENTATION_270: - y = xScaled + mXTranslate; - x = yScaledMax - (mRawSurfaceHeight - mSurfaceBottom); + y = xScaled; + x = yScaledMax; break; default: assert(false); } } -bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) { +bool TouchInputMapper::isPointInsidePhysicalFrame(int32_t x, int32_t y) const { const float xScaled = (x - mRawPointerAxes.x.minValue) * mXScale; const float yScaled = (y - mRawPointerAxes.y.minValue) * mYScale; @@ -4054,7 +4024,7 @@ std::pair TouchInputMapper::getMouseCursorPosition() const { void TouchInputMapper::setMouseCursorPosition(float x, float y) const { // Convert from InputReader's un-rotated coordinate space to PointerController's rotated // coordinate space that is oriented with the viewport. - rotatePoint(mViewport.orientation, x, y, mRawSurfaceWidth, mRawSurfaceHeight); + rotatePoint(mViewport.orientation, x, y, mDisplayWidth, mDisplayHeight); mPointerController->setPosition(x, y); } @@ -4071,7 +4041,7 @@ void TouchInputMapper::setTouchSpots(const PointerCoords* spotCoords, const uint // Convert from InputReader's un-rotated coordinate space to PointerController's rotated // coordinate space. - rotatePoint(mViewport.orientation, x, y, mRawSurfaceWidth, mRawSurfaceHeight); + rotatePoint(mViewport.orientation, x, y, mDisplayWidth, mDisplayHeight); outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_X, x); outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_Y, y); diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index 3340672021..496491b62d 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -406,8 +406,8 @@ protected: virtual void dumpParameters(std::string& dump); virtual void configureRawPointerAxes(); virtual void dumpRawPointerAxes(std::string& dump); - virtual void configureSurface(nsecs_t when, bool* outResetNeeded); - virtual void dumpSurface(std::string& dump); + virtual void configureInputDevice(nsecs_t when, bool* outResetNeeded); + virtual void dumpDisplay(std::string& dump); virtual void configureVirtualKeys(); virtual void dumpVirtualKeys(std::string& dump); virtual void parseCalibration(); @@ -426,39 +426,27 @@ private: // The components of the viewport are specified in the display's rotated orientation. DisplayViewport mViewport; - // The surface orientation, width and height set by configureSurface(). - // The width and height are derived from the viewport but are specified + // The width and height are obtained from the viewport and are specified // in the natural orientation. - // They could be used for calculating diagonal, scaling factors, and virtual keys. - int32_t mRawSurfaceWidth; - int32_t mRawSurfaceHeight; - - // The surface origin specifies how the surface coordinates should be translated - // to align with the logical display coordinate space. - // TODO(b/188939842): Remove surface coordinates when Per-Window Input Rotation is enabled. - int32_t mSurfaceLeft; - int32_t mSurfaceTop; - int32_t mSurfaceRight; - int32_t mSurfaceBottom; - - // Similar to the surface coordinates, but in the raw display coordinate space rather than in - // the logical coordinate space. + int32_t mDisplayWidth; + int32_t mDisplayHeight; + + // The physical frame is the rectangle in the display's coordinate space that maps to the + // the logical display frame. int32_t mPhysicalWidth; int32_t mPhysicalHeight; int32_t mPhysicalLeft; int32_t mPhysicalTop; - // The orientation may be different from the viewport orientation as it specifies - // the rotation of the surface coordinates required to produce the viewport's - // requested orientation, so it will depend on whether the device is orientation aware. - int32_t mSurfaceOrientation; + // The orientation of the input device relative to that of the display panel. It specifies + // the rotation of the input device coordinates required to produce the display panel + // orientation, so it will depend on whether the device is orientation aware. + int32_t mInputDeviceOrientation; // Translation and scaling factors, orientation-independent. - float mXTranslate; float mXScale; float mXPrecision; - float mYTranslate; float mYScale; float mYPrecision; @@ -808,13 +796,13 @@ private: // touchscreen. void updateTouchSpots(); - bool isPointInsideSurface(int32_t x, int32_t y); + bool isPointInsidePhysicalFrame(int32_t x, int32_t y) const; const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y); static void assignPointerIds(const RawState& last, RawState& current); const char* modeToString(DeviceMode deviceMode); - void rotateAndScale(float& x, float& y); + void rotateAndScale(float& x, float& y) const; // Wrapper methods for interfacing with PointerController. These are used to convert points // between the coordinate spaces used by InputReader and PointerController, if they differ. -- cgit v1.2.3-59-g8ed1b From b76f17d5f71e03f86a0f9ee05cc4614bb4461dce Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Wed, 3 Nov 2021 15:04:18 -0400 Subject: sf-latency: Wait on fence after each drawLayers call Bug: 193240340 Test: this Previously, the benchmark simply passed the fence to the next call, meaning that the next drawLayers could start before the GPU was finished. Explicitly wait for it inside the benchmark, so that we'll time both CPU and GPU work. Add comments describing such. Change-Id: I7f34636d6b3701b71eaa8d8435e947e258d2fa67 --- libs/renderengine/benchmark/RenderEngineBench.cpp | 33 ++++++++++++++--------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp index 719b855348..9ee7e4da9e 100644 --- a/libs/renderengine/benchmark/RenderEngineBench.cpp +++ b/libs/renderengine/benchmark/RenderEngineBench.cpp @@ -111,8 +111,7 @@ static std::unique_ptr createRenderEngine(RenderEngine::RenderEngi return RenderEngine::create(args); } -static std::shared_ptr allocateBuffer(RenderEngine& re, - uint32_t width, +static std::shared_ptr allocateBuffer(RenderEngine& re, uint32_t width, uint32_t height, uint64_t extraUsageFlags = 0, std::string name = "output") { @@ -160,11 +159,21 @@ static std::shared_ptr copyBuffer(RenderEngine& re, auto [status, drawFence] = re.drawLayers(display, layers, texture, kUseFrameBufferCache, base::unique_fd()).get(); - sp waitFence = new Fence(std::move(drawFence)); + sp waitFence = sp::make(std::move(drawFence)); waitFence->waitForever(LOG_TAG); return texture; } +/** + * Helper for timing calls to drawLayers. + * + * Caller needs to create RenderEngine and the LayerSettings, and this takes + * care of setting up the display, starting and stopping the timer, calling + * drawLayers, and saving (if --save is used). + * + * This times both the CPU and GPU work initiated by drawLayers. All work done + * outside of the for loop is excluded from the timing measurements. + */ static void benchDrawLayers(RenderEngine& re, const std::vector& layers, benchmark::State& benchState, const char* saveFileName) { auto [width, height] = getDisplaySize(); @@ -177,18 +186,16 @@ static void benchDrawLayers(RenderEngine& re, const std::vector& .maxLuminance = 500, }; - base::unique_fd fence; + // This loop starts and stops the timer. for (auto _ : benchState) { - auto [status, drawFence] = - re.drawLayers(display, layers, outputBuffer, kUseFrameBufferCache, std::move(fence)) - .get(); - fence = std::move(drawFence); + auto [status, drawFence] = re.drawLayers(display, layers, outputBuffer, + kUseFrameBufferCache, base::unique_fd()) + .get(); + sp waitFence = sp::make(std::move(drawFence)); + waitFence->waitForever(LOG_TAG); } if (renderenginebench::save() && saveFileName) { - sp waitFence = new Fence(std::move(fence)); - waitFence->waitForever(LOG_TAG); - // Copy to a CPU-accessible buffer so we can encode it. outputBuffer = copyBuffer(re, outputBuffer, GRALLOC_USAGE_SW_READ_OFTEN, "to_encode"); @@ -209,8 +216,8 @@ void BM_blur(benchmark::State& benchState) { // Initially use cpu access so we can decode into it with AImageDecoder. auto [width, height] = getDisplaySize(); - auto srcBuffer = allocateBuffer(*re, width, height, GRALLOC_USAGE_SW_WRITE_OFTEN, - "decoded_source"); + auto srcBuffer = + allocateBuffer(*re, width, height, GRALLOC_USAGE_SW_WRITE_OFTEN, "decoded_source"); { std::string srcImage = base::GetExecutableDirectory(); srcImage.append("/resources/homescreen.png"); -- cgit v1.2.3-59-g8ed1b From fd37d2a41512aa23135069d48b9811d0843fd4ac Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Wed, 3 Nov 2021 15:11:48 -0400 Subject: sf-latency: Explicitly time SKIA_GL_THREADED Bug: 193240340 Test: This My original intent for this benchmark was to time drawLayers, without worrying about threading overhead. But using SKIA_GL means that we do not execute mapExternalTextureBuffer ahead of time, so we have to do this work each frame. mapExternalTextureBuffer should be tracked by a separate benchmark. Change-Id: I0d58fdf67a6322f0bbc04835ab1cdb08b73bcf7b --- libs/renderengine/benchmark/RenderEngineBench.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp index 9ee7e4da9e..6c8f8e878b 100644 --- a/libs/renderengine/benchmark/RenderEngineBench.cpp +++ b/libs/renderengine/benchmark/RenderEngineBench.cpp @@ -46,8 +46,8 @@ std::string RenderEngineTypeName(RenderEngine::RenderEngineType type) { } /** - * Passed (indirectly - see RunSkiaGL) to Benchmark::Apply to create a Benchmark - * which specifies which RenderEngineType it uses. + * Passed (indirectly - see RunSkiaGLThreaded) to Benchmark::Apply to create a + * Benchmark which specifies which RenderEngineType it uses. * * This simplifies calling ->Arg(type)->Arg(type) and provides strings to make * it obvious which version is being run. @@ -62,10 +62,10 @@ static void AddRenderEngineType(benchmark::internal::Benchmark* b, } /** - * Run a benchmark once using SKIA_GL. + * Run a benchmark once using SKIA_GL_THREADED. */ -static void RunSkiaGL(benchmark::internal::Benchmark* b) { - AddRenderEngineType(b, RenderEngine::RenderEngineType::SKIA_GL); +static void RunSkiaGLThreaded(benchmark::internal::Benchmark* b) { + AddRenderEngineType(b, RenderEngine::RenderEngineType::SKIA_GL_THREADED); } /////////////////////////////////////////////////////////////////////////////// @@ -256,4 +256,4 @@ void BM_blur(benchmark::State& benchState) { benchDrawLayers(*re, layers, benchState, "blurred"); } -BENCHMARK(BM_blur)->Apply(RunSkiaGL); +BENCHMARK(BM_blur)->Apply(RunSkiaGLThreaded); -- cgit v1.2.3-59-g8ed1b From dd00c003aecab872f97bcf249e6a2503f6b06be6 Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Thu, 4 Nov 2021 16:54:38 +0100 Subject: SF: Don't update scheduler if desired active mode is not allowed Currently if we the desired active mode is not allowed we call desiredActiveModeChangeDone which also updates Scheduler with the desired mode. We should instead clear the desired mode. Bug: 190982486 Test: atest libsurfaceflinger_unittest Change-Id: I349fe3f14f4075be9e816b2d319e78603b27727d --- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c2dcd70166..c4f557ad67 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1259,7 +1259,7 @@ void SurfaceFlinger::performSetActiveMode() { const auto displayModeAllowed = display->refreshRateConfigs().isModeAllowed(desiredActiveMode->mode->getId()); if (!displayModeAllowed) { - desiredActiveModeChangeDone(display); + clearDesiredActiveModeState(display); continue; } -- cgit v1.2.3-59-g8ed1b From 1d667a23ef2f20a57f51ede6842cbdf0b327c265 Mon Sep 17 00:00:00 2001 From: Neharika Jali Date: Mon, 25 Oct 2021 19:36:18 +0000 Subject: Periodically free cache below high storage threshold Bug: 203650385 Test: atest installd_cache_test Ignore-AOSP-First: This CL is to be submitted in a topic aimed for T release Change-Id: Ia01ab02a77b6365585fafc974d2c68349b5e9e62 --- cmds/installd/InstalldNativeService.cpp | 43 ++++++++++++++++---------- cmds/installd/binder/android/os/IInstalld.aidl | 2 ++ cmds/installd/tests/installd_cache_test.cpp | 30 ++++++++++++++++++ 3 files changed, 58 insertions(+), 17 deletions(-) diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index bb83db5b59..fffcdd10d9 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -1353,6 +1353,7 @@ binder::Status InstalldNativeService::freeCache(const std::optional const char* uuid_ = uuid ? uuid->c_str() : nullptr; auto data_path = create_data_path(uuid_); auto noop = (flags & FLAG_FREE_CACHE_NOOP); + auto defy_target = (flags & FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES); int64_t free = data_disk_free(data_path); if (free < 0) { @@ -1361,11 +1362,13 @@ binder::Status InstalldNativeService::freeCache(const std::optional int64_t cleared = 0; int64_t needed = targetFreeBytes - free; - LOG(DEBUG) << "Device " << data_path << " has " << free << " free; requested " - << targetFreeBytes << "; needed " << needed; + if (!defy_target) { + LOG(DEBUG) << "Device " << data_path << " has " << free << " free; requested " + << targetFreeBytes << "; needed " << needed; - if (free >= targetFreeBytes) { - return ok(); + if (free >= targetFreeBytes) { + return ok(); + } } if (flags & FLAG_FREE_CACHE_V2) { @@ -1479,15 +1482,17 @@ binder::Status InstalldNativeService::freeCache(const std::optional cleared += item->size; } - // Verify that we're actually done before bailing, since sneaky - // apps might be using hardlinks - if (needed <= 0) { - free = data_disk_free(data_path); - needed = targetFreeBytes - free; + if (!defy_target) { + // Verify that we're actually done before bailing, since sneaky + // apps might be using hardlinks if (needed <= 0) { - break; - } else { - LOG(WARNING) << "Expected to be done but still need " << needed; + free = data_disk_free(data_path); + needed = targetFreeBytes - free; + if (needed <= 0) { + break; + } else { + LOG(WARNING) << "Expected to be done but still need " << needed; + } } } } @@ -1497,12 +1502,16 @@ binder::Status InstalldNativeService::freeCache(const std::optional return error("Legacy cache logic no longer supported"); } - free = data_disk_free(data_path); - if (free >= targetFreeBytes) { - return ok(); + if (!defy_target) { + free = data_disk_free(data_path); + if (free >= targetFreeBytes) { + return ok(); + } else { + return error(StringPrintf("Failed to free up %" PRId64 " on %s; final free space %" PRId64, + targetFreeBytes, data_path.c_str(), free)); + } } else { - return error(StringPrintf("Failed to free up %" PRId64 " on %s; final free space %" PRId64, - targetFreeBytes, data_path.c_str(), free)); + return ok(); } } diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index 9c51ff749d..3b6b3540e6 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -138,6 +138,8 @@ interface IInstalld { const int FLAG_FREE_CACHE_V2 = 0x100; const int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 0x200; const int FLAG_FREE_CACHE_NOOP = 0x400; + // Set below flag to clear cache irrespective of target free bytes required + const int FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES = 0x800; const int FLAG_USE_QUOTA = 0x1000; const int FLAG_FORCE = 0x2000; diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp index 9a1e17eb20..5cb83fdffe 100644 --- a/cmds/installd/tests/installd_cache_test.cpp +++ b/cmds/installd/tests/installd_cache_test.cpp @@ -42,6 +42,7 @@ constexpr int64_t kTbInBytes = 1024 * kGbInBytes; #define FLAG_FREE_CACHE_V2 InstalldNativeService::FLAG_FREE_CACHE_V2 #define FLAG_FREE_CACHE_V2_DEFY_QUOTA InstalldNativeService::FLAG_FREE_CACHE_V2_DEFY_QUOTA +#define FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES InstalldNativeService::FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES int get_property(const char *key, char *value, const char *default_value) { return property_get(key, value, default_value); @@ -180,6 +181,35 @@ TEST_F(CacheTest, FreeCache_NonAggressive) { EXPECT_EQ(0, exists("com.example/cache/foo/two")); } +TEST_F(CacheTest, FreeCache_DefyTargetFreeBytes) { + LOG(INFO) << "FreeCache_DefyTargetFreeBytes"; + + mkdir("com.example"); + touch("com.example/normal", 1 * kMbInBytes, 60); + mkdir("com.example/cache"); + mkdir("com.example/cache/foo"); + touch("com.example/cache/foo/one", 65 * kMbInBytes, 60); + touch("com.example/cache/foo/two", 2 * kMbInBytes, 120); + + EXPECT_EQ(0, exists("com.example/normal")); + EXPECT_EQ(0, exists("com.example/cache/foo/one")); + EXPECT_EQ(0, exists("com.example/cache/foo/two")); + + service->freeCache(testUuid, kMbInBytes, FLAG_FREE_CACHE_V2 + | FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES); + + EXPECT_EQ(0, exists("com.example/normal")); + EXPECT_EQ(-1, exists("com.example/cache/foo/one")); + EXPECT_EQ(0, exists("com.example/cache/foo/two")); + + service->freeCache(testUuid, kMbInBytes, FLAG_FREE_CACHE_V2 + | FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES); + + EXPECT_EQ(0, exists("com.example/normal")); + EXPECT_EQ(-1, exists("com.example/cache/foo/one")); + EXPECT_EQ(0, exists("com.example/cache/foo/two")); +} + TEST_F(CacheTest, FreeCache_Age) { LOG(INFO) << "FreeCache_Age"; -- cgit v1.2.3-59-g8ed1b From 9051fb1885df913eecfa9072155797bdaf05d278 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 5 Nov 2021 16:21:06 -0700 Subject: BBQ: Clean up acquire states on BQ disconnect When the producer disconnects, all buffers in the queue will be freed. So clean up the bbq acquire state and handle any pending release callbacks. If we do get a release callback for a pending buffer for a disconnected queue, we cannot release the buffer back to the queue. So track these separately and drop the release callbacks as they come. Transaction callbacks are still expected to come in the order they were submitted regardless of buffer queue state. So we can continue to handle the pending transactions and transaction complete callbacks. When the queue is reconnected, the queue will increment the framenumbers starting from the last queued framenumber. Bug: 201482894 Test: atest BLASTBufferQueueTest Change-Id: I110530c2135804fc7b9545602dd6430014cad85c --- libs/gui/BLASTBufferQueue.cpp | 73 +++++++++++++++++++++++++--- libs/gui/include/gui/BLASTBufferQueue.h | 12 +++++ services/surfaceflinger/BufferStateLayer.cpp | 2 +- services/surfaceflinger/BufferStateLayer.h | 1 + 4 files changed, 80 insertions(+), 8 deletions(-) diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 9080822f92..9cb7c88956 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -58,13 +58,22 @@ namespace android { ALOGE("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__) void BLASTBufferItemConsumer::onDisconnect() { - Mutex::Autolock lock(mMutex); - mPreviouslyConnected = mCurrentlyConnected; - mCurrentlyConnected = false; - if (mPreviouslyConnected) { - mDisconnectEvents.push(mCurrentFrameNumber); + { + Mutex::Autolock lock(mMutex); + mPreviouslyConnected = mCurrentlyConnected; + mCurrentlyConnected = false; + if (mPreviouslyConnected) { + mDisconnectEvents.push(mCurrentFrameNumber); + } + mFrameEventHistory.onDisconnect(); + } + + { + std::scoped_lock lock(mBufferQueueMutex); + if (mBLASTBufferQueue != nullptr) { + mBLASTBufferQueue->onProducerDisconnect(); + } } - mFrameEventHistory.onDisconnect(); } void BLASTBufferItemConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, @@ -202,7 +211,11 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, } SurfaceComposerClient::Transaction t; - const bool setBackpressureFlag = !SurfaceControl::isSameSurface(mSurfaceControl, surface); + bool setBackpressureFlag = false; + if (!SurfaceControl::isSameSurface(mSurfaceControl, surface)) { + mSurfaceControlSwapCount++; + setBackpressureFlag = true; + } bool applyTransaction = false; // Always update the native object even though they might have the same layer handle, so we can @@ -388,6 +401,19 @@ void BLASTBufferQueue::releaseBufferCallback( std::unique_lock _lock{mMutex}; BQA_LOGV("releaseBufferCallback %s", id.to_string().c_str()); + const auto it = mFreedBuffers.find(id); + if (it != mFreedBuffers.end()) { + mFreedBuffers.erase(it); + BQA_LOGV("releaseBufferCallback ignoring freed buffer %s", id.to_string().c_str()); + return; + } + + if (mFreedBuffers.size() != 0 && mLogMissingReleaseCallback) { + BQA_LOGD("Unexpected out of order buffer release. mFreedBuffer count=%d", + static_cast(mFreedBuffers.size())); + mLogMissingReleaseCallback = false; + } + // Calculate how many buffers we need to hold before we release them back // to the buffer queue. This will prevent higher latency when we are running // on a lower refresh rate than the max supported. We only do that for EGL @@ -593,6 +619,12 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { ATRACE_CALL(); std::unique_lock _lock{mMutex}; + if ((mSurfaceControlSwapCount > mProducerDisconnectCount) && mLogScSwap) { + BQA_LOGD("Expected producer disconnect sc swap count=%d bq disconnect count=%d", + mSurfaceControlSwapCount, mProducerDisconnectCount); + mLogScSwap = false; + } + const bool nextTransactionSet = mNextTransaction != nullptr; BQA_LOGV("onFrameAvailable-start nextTransactionSet=%s", boolToString(nextTransactionSet)); if (nextTransactionSet) { @@ -959,4 +991,31 @@ uint64_t BLASTBufferQueue::getLastAcquiredFrameNum() { return mLastAcquiredFrameNumber; } +// When the producer disconnects, all buffers in the queue will be freed. So clean up the bbq +// acquire state and handle any pending release callbacks. If we do get a release callback for a +// pending buffer for a disconnected queue, we cannot release the buffer back to the queue. So track +// these separately and drop the release callbacks as they come. + +// Transaction callbacks are still expected to come in the order they were submitted regardless of +// buffer queue state. So we can continue to handles the pending transactions and transaction +// complete callbacks. When the queue is reconnected, the queue will increment the framenumbers +// starting from the last queued framenumber. +void BLASTBufferQueue::onProducerDisconnect() { + BQA_LOGV("onProducerDisconnect"); + std::scoped_lock _lock{mMutex}; + // reset counts since the queue has been disconnected and all buffers have been freed. + mNumFrameAvailable = 0; + mNumAcquired = 0; + + // Track submitted buffers in a different container so we can handle any pending release buffer + // callbacks without affecting the BBQ acquire state. + mFreedBuffers.insert(mSubmitted.begin(), mSubmitted.end()); + mSubmitted.clear(); + mPendingRelease.clear(); + mProducerDisconnectCount++; + mCallbackCV.notify_all(); + mLogMissingReleaseCallback = true; + mLogScSwap = true; +} + } // namespace android diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 3881620f3d..72567e3f93 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -109,6 +109,8 @@ public: uint32_t getLastTransformHint() const; uint64_t getLastAcquiredFrameNum(); + void onProducerDisconnect(); + virtual ~BLASTBufferQueue(); private: @@ -156,6 +158,12 @@ private: std::unordered_map mSubmitted GUARDED_BY(mMutex); + // Keep a reference to the submitted buffers that were freed so we can drop the buffer quietly + // when we get the release callback from flinger. This can happen if the client had disconnected + // from the queue. + std::unordered_map mFreedBuffers + GUARDED_BY(mMutex); + // Keep a queue of the released buffers instead of immediately releasing // the buffers back to the buffer queue. This would be controlled by SF // setting the max acquired buffer count. @@ -240,6 +248,10 @@ private: uint32_t mCurrentMaxAcquiredBufferCount; bool mWaitForTransactionCallback = false; + bool mLogScSwap = true; + bool mLogMissingReleaseCallback = true; + uint32_t mSurfaceControlSwapCount = 0; + uint32_t mProducerDisconnectCount = 0; }; } // namespace android diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index c0753f9d47..25fb6ce2ae 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -404,7 +404,7 @@ bool BufferStateLayer::setBuffer(const BufferData& bufferData, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, std::optional dequeueTime, const FrameTimelineInfo& info) { - ATRACE_CALL(); + ATRACE_NAME(mSetBufferTraceTag.c_str()); const std::shared_ptr& buffer = getBufferFromBufferData(bufferData); diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index eea700cf7b..3aa60826d0 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -153,6 +153,7 @@ private: static constexpr int kPendingClassificationMaxSurfaceFrames = 25; const std::string mBlastTransactionName{"BufferTX - " + mName}; + const std::string mSetBufferTraceTag{"setBuffer - " + mName}; // This integer is incremented everytime a buffer arrives at the server for this layer, // and decremented when a buffer is dropped or latched. When changed the integer is exported // to systrace with ATRACE_INT and mBlastTransactionName. This way when debugging perf it is -- cgit v1.2.3-59-g8ed1b From 7fb9e5a047292114552ba6523bd790269b6cf937 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 8 Nov 2021 12:44:05 -0800 Subject: SF: Create layers with layerid When recreating layer states from transaction traces we need to create layers with a specific layer id. Add the layer id as part of LayerCreationArgs and pass the struct around instead of individual args. Test: presubmit Bug: 200284593 Change-Id: I029cdb5362d1926deaf2ce64f70a1882a418705b --- services/surfaceflinger/BufferQueueLayer.cpp | 2 +- services/surfaceflinger/BufferQueueLayer.h | 5 + services/surfaceflinger/BufferStateLayer.cpp | 2 +- services/surfaceflinger/Client.cpp | 45 +++---- services/surfaceflinger/ContainerLayer.cpp | 3 +- services/surfaceflinger/EffectLayer.cpp | 3 +- services/surfaceflinger/Layer.cpp | 15 +-- services/surfaceflinger/Layer.h | 10 +- services/surfaceflinger/LayerRenderArea.cpp | 4 +- services/surfaceflinger/MonitoredProducer.cpp | 8 +- services/surfaceflinger/SurfaceFlinger.cpp | 132 +++++---------------- services/surfaceflinger/SurfaceFlinger.h | 44 ++----- .../tests/SurfaceInterceptor_test.cpp | 4 +- .../tests/unittests/CompositionTest.cpp | 5 +- .../tests/unittests/FpsReporterTest.cpp | 3 +- .../tests/unittests/GameModeTest.cpp | 2 +- .../tests/unittests/RefreshRateSelectionTest.cpp | 7 +- .../tests/unittests/SetFrameRateTest.cpp | 6 +- .../tests/unittests/TransactionFrameTracerTest.cpp | 2 +- .../unittests/TransactionSurfaceFrameTest.cpp | 2 +- .../unittests/TunnelModeEnabledReporterTest.cpp | 3 +- .../tests/unittests/mock/MockLayer.h | 2 +- 22 files changed, 99 insertions(+), 210 deletions(-) diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 28c387e5bd..dec7cc0806 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -523,7 +523,7 @@ void BufferQueueLayer::gatherBufferInfo() { } sp BufferQueueLayer::createClone() { - LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0, LayerMetadata()); + LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata()); args.textureName = mTextureName; sp layer = mFlinger->getFactory().createBufferQueueLayer(args); layer->setInitialValuesForClone(this); diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index dfdb5c055d..c6e0727806 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -62,6 +62,11 @@ public: status_t setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format); sp getProducer() const; + void setSizeForTest(uint32_t w, uint32_t h) { + mDrawingState.active_legacy.w = w; + mDrawingState.active_legacy.h = h; + } + protected: void gatherBufferInfo() override; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index b6cbbb658f..88e3fb6744 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -890,7 +890,7 @@ Rect BufferStateLayer::computeBufferCrop(const State& s) { } sp BufferStateLayer::createClone() { - LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0, LayerMetadata()); + LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata()); args.textureName = mTextureName; sp layer = mFlinger->getFactory().createBufferStateLayer(args); layer->mHwcSlotGenerator = mHwcSlotGenerator; diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp index 8da2e24aa4..0a8ebec9f3 100644 --- a/services/surfaceflinger/Client.cpp +++ b/services/surfaceflinger/Client.cpp @@ -72,35 +72,28 @@ sp Client::getLayerUser(const sp& handle) const return lbc; } -status_t Client::createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags, const sp& parentHandle, - LayerMetadata metadata, sp* handle, - sp* gbp, int32_t* outLayerId, - uint32_t* outTransformHint) { +status_t Client::createSurface(const String8& name, uint32_t /* w */, uint32_t /* h */, + PixelFormat /* format */, uint32_t flags, + const sp& parentHandle, LayerMetadata metadata, + sp* outHandle, sp* /* gbp */, + int32_t* outLayerId, uint32_t* outTransformHint) { // We rely on createLayer to check permissions. - return mFlinger->createLayer(name, this, w, h, format, flags, std::move(metadata), handle, gbp, - parentHandle, outLayerId, nullptr, outTransformHint); + LayerCreationArgs args(mFlinger.get(), this, name.c_str(), flags, std::move(metadata)); + return mFlinger->createLayer(args, outHandle, parentHandle, outLayerId, nullptr, + outTransformHint); } -status_t Client::createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h, - PixelFormat format, uint32_t flags, - const sp& parent, - LayerMetadata metadata, sp* handle, - sp* gbp, int32_t* outLayerId, - uint32_t* outTransformHint) { - if (mFlinger->authenticateSurfaceTexture(parent) == false) { - ALOGE("failed to authenticate surface texture"); - return BAD_VALUE; - } - - const auto& layer = (static_cast(parent.get()))->getLayer(); - if (layer == nullptr) { - ALOGE("failed to find parent layer"); - return BAD_VALUE; - } - - return mFlinger->createLayer(name, this, w, h, format, flags, std::move(metadata), handle, gbp, - nullptr, outLayerId, layer, outTransformHint); +status_t Client::createWithSurfaceParent(const String8& /* name */, uint32_t /* w */, + uint32_t /* h */, PixelFormat /* format */, + uint32_t /* flags */, + const sp& /* parent */, + LayerMetadata /* metadata */, sp* /* handle */, + sp* /* gbp */, + int32_t* /* outLayerId */, + uint32_t* /* outTransformHint */) { + // This api does not make sense with blast since SF no longer tracks IGBP. This api should be + // removed. + return BAD_VALUE; } status_t Client::mirrorSurface(const sp& mirrorFromHandle, sp* outHandle, diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp index 841e79f8af..3ccc229261 100644 --- a/services/surfaceflinger/ContainerLayer.cpp +++ b/services/surfaceflinger/ContainerLayer.cpp @@ -36,8 +36,7 @@ bool ContainerLayer::isVisible() const { sp ContainerLayer::createClone() { sp layer = mFlinger->getFactory().createContainerLayer( - LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0, - LayerMetadata())); + LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata())); layer->setInitialValuesForClone(this); return layer; } diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp index 86c6b2161c..845176c112 100644 --- a/services/surfaceflinger/EffectLayer.cpp +++ b/services/surfaceflinger/EffectLayer.cpp @@ -136,8 +136,7 @@ ui::Dataspace EffectLayer::getDataSpace() const { sp EffectLayer::createClone() { sp layer = mFlinger->getFactory().createEffectLayer( - LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0, - LayerMetadata())); + LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata())); layer->setInitialValuesForClone(this); return layer; } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d85e843d83..3d189d681b 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -87,11 +87,12 @@ using gui::WindowInfo; std::atomic Layer::sSequence{1}; Layer::Layer(const LayerCreationArgs& args) - : mFlinger(args.flinger), + : sequence(args.sequence.value_or(sSequence++)), + mFlinger(args.flinger), mName(base::StringPrintf("%s#%d", args.name.c_str(), sequence)), mClientRef(args.client), - mWindowType( - static_cast(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0))) { + mWindowType(static_cast(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0))), + mLayerCreationFlags(args.flags) { uint32_t layerFlags = 0; if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden; if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque; @@ -99,8 +100,6 @@ Layer::Layer(const LayerCreationArgs& args) if (args.flags & ISurfaceComposerClient::eSkipScreenshot) layerFlags |= layer_state_t::eLayerSkipScreenshot; - mDrawingState.active_legacy.w = args.w; - mDrawingState.active_legacy.h = args.h; mDrawingState.flags = layerFlags; mDrawingState.active_legacy.transform.set(0, 0); mDrawingState.crop.makeInvalid(); @@ -185,12 +184,10 @@ Layer::~Layer() { } LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp client, std::string name, - uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata) + uint32_t flags, LayerMetadata metadata) : flinger(flinger), client(std::move(client)), name(std::move(name)), - w(w), - h(h), flags(flags), metadata(std::move(metadata)) { IPCThreadState* ipc = IPCThreadState::self(); @@ -887,7 +884,7 @@ bool Layer::setBackgroundColor(const half3& color, float alpha, ui::Dataspace da uint32_t flags = ISurfaceComposerClient::eFXSurfaceEffect; std::string name = mName + "BackgroundColorLayer"; mDrawingState.bgColorLayer = mFlinger->getFactory().createEffectLayer( - LayerCreationArgs(mFlinger.get(), nullptr, std::move(name), 0, 0, flags, + LayerCreationArgs(mFlinger.get(), nullptr, std::move(name), flags, LayerMetadata())); // add to child list diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index b79903d11b..3da07e824d 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -85,20 +85,18 @@ class SurfaceFrame; } // namespace frametimeline struct LayerCreationArgs { - LayerCreationArgs(SurfaceFlinger*, sp, std::string name, uint32_t w, uint32_t h, - uint32_t flags, LayerMetadata); + LayerCreationArgs(SurfaceFlinger*, sp, std::string name, uint32_t flags, LayerMetadata); SurfaceFlinger* flinger; const sp client; std::string name; - uint32_t w; - uint32_t h; uint32_t flags; LayerMetadata metadata; pid_t callingPid; uid_t callingUid; uint32_t textureName; + std::optional sequence = std::nullopt; }; class Layer : public virtual RefBase, compositionengine::LayerFE { @@ -879,7 +877,7 @@ public: // Layer serial number. This gives layers an explicit ordering, so we // have a stable sort order when their layer stack and Z-order are // the same. - int32_t sequence{sSequence++}; + const int32_t sequence; bool mPendingHWCDestroy{false}; @@ -1117,6 +1115,8 @@ private: const std::vector getBlurRegions() const; bool mIsAtRoot = false; + + uint32_t mLayerCreationFlags; }; std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate); diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp index 11fe6d0755..a1e14559e9 100644 --- a/services/surfaceflinger/LayerRenderArea.cpp +++ b/services/surfaceflinger/LayerRenderArea.cpp @@ -112,12 +112,10 @@ void LayerRenderArea::render(std::function drawLayers) { } drawLayers(); } else { - uint32_t w = static_cast(getWidth()); - uint32_t h = static_cast(getHeight()); // In the "childrenOnly" case we reparent the children to a screenshot // layer which has no properties set and which does not draw. sp screenshotParentLayer = mFlinger.getFactory().createContainerLayer( - {&mFlinger, nullptr, "Screenshot Parent"s, w, h, 0, LayerMetadata()}); + {&mFlinger, nullptr, "Screenshot Parent"s, 0, LayerMetadata()}); ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop); drawLayers(); diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp index 6b2d745998..df76f50112 100644 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ b/services/surfaceflinger/MonitoredProducer.cpp @@ -33,13 +33,7 @@ MonitoredProducer::MonitoredProducer(const sp& producer, mFlinger(flinger), mLayer(layer) {} -MonitoredProducer::~MonitoredProducer() { - // Remove ourselves from SurfaceFlinger's list. We do this asynchronously - // because we don't know where this destructor is called from. It could be - // called with the mStateLock held, leading to a dead-lock (it actually - // happens). - mFlinger->removeGraphicBufferProducerAsync(onAsBinder()); -} +MonitoredProducer::~MonitoredProducer() {} status_t MonitoredProducer::requestBuffer(int slot, sp* buf) { return mProducer->requestBuffer(slot, buf); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c2dcd70166..5a6a8ce05a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -904,9 +904,8 @@ bool SurfaceFlinger::authenticateSurfaceTexture( } bool SurfaceFlinger::authenticateSurfaceTextureLocked( - const sp& bufferProducer) const { - sp surfaceTextureBinder(IInterface::asBinder(bufferProducer)); - return mGraphicBufferProducerList.count(surfaceTextureBinder.get()) > 0; + const sp& /* bufferProducer */) const { + return false; } status_t SurfaceFlinger::getSupportedFrameTimestamps( @@ -3355,20 +3354,15 @@ bool SurfaceFlinger::latchBuffers() { } status_t SurfaceFlinger::addClientLayer(const sp& client, const sp& handle, - const sp& gbc, const sp& lbc, - const wp& parent, bool addToRoot, - uint32_t* outTransformHint) { + const sp& lbc, const wp& parent, + bool addToRoot, uint32_t* outTransformHint) { if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) { ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(), ISurfaceComposer::MAX_LAYERS); return NO_MEMORY; } - wp initialProducer; - if (gbc != nullptr) { - initialProducer = IInterface::asBinder(gbc); - } - setLayerCreatedState(handle, lbc, parent, initialProducer, addToRoot); + setLayerCreatedState(handle, lbc, parent, addToRoot); // Create a transaction includes the initial parent and producer. Vector states; @@ -3384,7 +3378,9 @@ status_t SurfaceFlinger::addClientLayer(const sp& client, const spattachLayer(handle, lbc); + if (client != nullptr) { + client->attachLayer(handle, lbc); + } return setTransactionState(FrameTimelineInfo{}, states, displays, 0 /* flags */, nullptr, InputWindowCommands{}, -1 /* desiredPresentTime */, @@ -3392,13 +3388,6 @@ status_t SurfaceFlinger::addClientLayer(const sp& client, const sp& binder) { - static_cast(schedule([=] { - Mutex::Autolock lock(mStateLock); - mGraphicBufferProducerList.erase(binder); - })); -} - uint32_t SurfaceFlinger::getTransactionFlags() const { return mTransactionFlags; } @@ -4281,17 +4270,14 @@ status_t SurfaceFlinger::mirrorLayer(const sp& client, const sp sp mirrorLayer; sp mirrorFrom; - std::string layerName = "MirrorRoot"; - { Mutex::Autolock _l(mStateLock); mirrorFrom = fromHandle(mirrorFromHandle).promote(); if (!mirrorFrom) { return NAME_NOT_FOUND; } - - status_t result = createContainerLayer(client, std::move(layerName), -1, -1, 0, - LayerMetadata(), outHandle, &mirrorLayer); + LayerCreationArgs args(this, client, "MirrorRoot", 0, LayerMetadata()); + status_t result = createContainerLayer(args, outHandle, &mirrorLayer); if (result != NO_ERROR) { return result; } @@ -4300,22 +4286,13 @@ status_t SurfaceFlinger::mirrorLayer(const sp& client, const sp } *outLayerId = mirrorLayer->sequence; - return addClientLayer(client, *outHandle, nullptr, mirrorLayer, nullptr, false, - nullptr /* outTransformHint */); + return addClientLayer(client, *outHandle, mirrorLayer /* layer */, nullptr /* parent */, + false /* addAsRoot */, nullptr /* outTransformHint */); } -status_t SurfaceFlinger::createLayer(const String8& name, const sp& client, uint32_t w, - uint32_t h, PixelFormat format, uint32_t flags, - LayerMetadata metadata, sp* handle, - sp* gbp, +status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, sp* outHandle, const sp& parentHandle, int32_t* outLayerId, const sp& parentLayer, uint32_t* outTransformHint) { - if (int32_t(w|h) < 0) { - ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)", - int(w), int(h)); - return BAD_VALUE; - } - ALOG_ASSERT(parentLayer == nullptr || parentHandle == nullptr, "Expected only one of parentLayer or parentHandle to be non-null. " "Programmer error?"); @@ -4324,40 +4301,22 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie sp layer; - std::string layerName{name.string()}; - - switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { + switch (args.flags & ISurfaceComposerClient::eFXSurfaceMask) { case ISurfaceComposerClient::eFXSurfaceBufferQueue: case ISurfaceComposerClient::eFXSurfaceBufferState: { - result = createBufferStateLayer(client, std::move(layerName), w, h, flags, - std::move(metadata), handle, &layer); + result = createBufferStateLayer(args, outHandle, &layer); std::atomic* pendingBufferCounter = layer->getPendingBufferCounter(); if (pendingBufferCounter) { std::string counterName = layer->getPendingBufferCounterName(); - mBufferCountTracker.add((*handle)->localBinder(), counterName, + mBufferCountTracker.add((*outHandle)->localBinder(), counterName, pendingBufferCounter); } } break; case ISurfaceComposerClient::eFXSurfaceEffect: - // check if buffer size is set for color layer. - if (w > 0 || h > 0) { - ALOGE("createLayer() failed, w or h cannot be set for color layer (w=%d, h=%d)", - int(w), int(h)); - return BAD_VALUE; - } - - result = createEffectLayer(client, std::move(layerName), w, h, flags, - std::move(metadata), handle, &layer); + result = createEffectLayer(args, outHandle, &layer); break; case ISurfaceComposerClient::eFXSurfaceContainer: - // check if buffer size is set for container layer. - if (w > 0 || h > 0) { - ALOGE("createLayer() failed, w or h cannot be set for container layer (w=%d, h=%d)", - int(w), int(h)); - return BAD_VALUE; - } - result = createContainerLayer(client, std::move(layerName), w, h, flags, - std::move(metadata), handle, &layer); + result = createContainerLayer(args, outHandle, &layer); break; default: result = BAD_VALUE; @@ -4377,7 +4336,7 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie if (parentLayer != nullptr) { addToRoot = false; } - result = addClientLayer(client, *handle, *gbp, layer, parent, addToRoot, outTransformHint); + result = addClientLayer(args.client, *outHandle, layer, parent, addToRoot, outTransformHint); if (result != NO_ERROR) { return result; } @@ -4387,9 +4346,7 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie return result; } -status_t SurfaceFlinger::createBufferQueueLayer(const sp& client, std::string name, - uint32_t w, uint32_t h, uint32_t flags, - LayerMetadata metadata, PixelFormat& format, +status_t SurfaceFlinger::createBufferQueueLayer(LayerCreationArgs& args, PixelFormat& format, sp* handle, sp* gbp, sp* outLayer) { @@ -4405,7 +4362,6 @@ status_t SurfaceFlinger::createBufferQueueLayer(const sp& client, std::s } sp layer; - LayerCreationArgs args(this, client, std::move(name), w, h, flags, std::move(metadata)); args.textureName = getNewTexture(); { // Grab the SF state lock during this since it's the only safe way to access @@ -4415,7 +4371,7 @@ status_t SurfaceFlinger::createBufferQueueLayer(const sp& client, std::s layer = getFactory().createBufferQueueLayer(args); } - status_t err = layer->setDefaultBufferProperties(w, h, format); + status_t err = layer->setDefaultBufferProperties(0, 0, format); if (err == NO_ERROR) { *handle = layer->getHandle(); *gbp = layer->getProducer(); @@ -4426,34 +4382,24 @@ status_t SurfaceFlinger::createBufferQueueLayer(const sp& client, std::s return err; } -status_t SurfaceFlinger::createBufferStateLayer(const sp& client, std::string name, - uint32_t w, uint32_t h, uint32_t flags, - LayerMetadata metadata, sp* handle, +status_t SurfaceFlinger::createBufferStateLayer(LayerCreationArgs& args, sp* handle, sp* outLayer) { - LayerCreationArgs args(this, client, std::move(name), w, h, flags, std::move(metadata)); args.textureName = getNewTexture(); - sp layer = getFactory().createBufferStateLayer(args); - *handle = layer->getHandle(); - *outLayer = layer; - + *outLayer = getFactory().createBufferStateLayer(args); + *handle = (*outLayer)->getHandle(); return NO_ERROR; } -status_t SurfaceFlinger::createEffectLayer(const sp& client, std::string name, uint32_t w, - uint32_t h, uint32_t flags, LayerMetadata metadata, - sp* handle, sp* outLayer) { - *outLayer = getFactory().createEffectLayer( - {this, client, std::move(name), w, h, flags, std::move(metadata)}); +status_t SurfaceFlinger::createEffectLayer(LayerCreationArgs& args, sp* handle, + sp* outLayer) { + *outLayer = getFactory().createEffectLayer(args); *handle = (*outLayer)->getHandle(); return NO_ERROR; } -status_t SurfaceFlinger::createContainerLayer(const sp& client, std::string name, - uint32_t w, uint32_t h, uint32_t flags, - LayerMetadata metadata, sp* handle, +status_t SurfaceFlinger::createContainerLayer(LayerCreationArgs& args, sp* handle, sp* outLayer) { - *outLayer = getFactory().createContainerLayer( - {this, client, std::move(name), w, h, flags, std::move(metadata)}); + *outLayer = getFactory().createContainerLayer(args); *handle = (*outLayer)->getHandle(); return NO_ERROR; } @@ -5039,8 +4985,6 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co */ colorizer.bold(result); StringAppendF(&result, "Visible layers (count = %zu)\n", mNumLayers.load()); - StringAppendF(&result, "GraphicBufferProducers: %zu, max %zu\n", - mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize); colorizer.reset(result); { @@ -6802,11 +6746,10 @@ void TransactionState::traverseStatesWithBuffers( } void SurfaceFlinger::setLayerCreatedState(const sp& handle, const wp& layer, - const wp parent, const wp& producer, - bool addToRoot) { + const wp parent, bool addToRoot) { Mutex::Autolock lock(mCreatedLayersLock); mCreatedLayers[handle->localBinder()] = - std::make_unique(layer, parent, producer, addToRoot); + std::make_unique(layer, parent, addToRoot); } auto SurfaceFlinger::getLayerCreatedState(const sp& handle) { @@ -6867,19 +6810,6 @@ sp SurfaceFlinger::handleLayerCreatedLocked(const sp& handle) { layer->updateTransformHint(mActiveDisplayTransformHint); - if (state->initialProducer != nullptr) { - mGraphicBufferProducerList.insert(state->initialProducer); - LOG_ALWAYS_FATAL_IF(mGraphicBufferProducerList.size() > mMaxGraphicBufferProducerListSize, - "Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers", - mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize, - mNumLayers.load()); - if (mGraphicBufferProducerList.size() > mGraphicBufferProducerListSizeLogThreshold) { - ALOGW("Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers", - mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize, - mNumLayers.load()); - } - } - mInterceptor->saveSurfaceCreation(layer); return layer; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index bf628dc309..b432f246c0 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -763,29 +763,23 @@ private: /* * Layer management */ - status_t createLayer(const String8& name, const sp& client, uint32_t w, uint32_t h, - PixelFormat format, uint32_t flags, LayerMetadata metadata, - sp* handle, sp* gbp, + status_t createLayer(LayerCreationArgs& args, sp* outHandle, const sp& parentHandle, int32_t* outLayerId, const sp& parentLayer = nullptr, uint32_t* outTransformHint = nullptr); - status_t createBufferQueueLayer(const sp& client, std::string name, uint32_t w, - uint32_t h, uint32_t flags, LayerMetadata metadata, - PixelFormat& format, sp* outHandle, - sp* outGbp, sp* outLayer); + status_t createBufferQueueLayer(LayerCreationArgs& args, PixelFormat& format, + sp* outHandle, sp* outGbp, + sp* outLayer); - status_t createBufferStateLayer(const sp& client, std::string name, uint32_t w, - uint32_t h, uint32_t flags, LayerMetadata metadata, - sp* outHandle, sp* outLayer); + status_t createBufferStateLayer(LayerCreationArgs& args, sp* outHandle, + sp* outLayer); - status_t createEffectLayer(const sp& client, std::string name, uint32_t w, uint32_t h, - uint32_t flags, LayerMetadata metadata, sp* outHandle, + status_t createEffectLayer(LayerCreationArgs& args, sp* outHandle, sp* outLayer); - status_t createContainerLayer(const sp& client, std::string name, uint32_t w, - uint32_t h, uint32_t flags, LayerMetadata metadata, - sp* outHandle, sp* outLayer); + status_t createContainerLayer(LayerCreationArgs& args, sp* outHandle, + sp* outLayer); status_t mirrorLayer(const sp& client, const sp& mirrorFromHandle, sp* outHandle, int32_t* outLayerId); @@ -798,8 +792,7 @@ private: // add a layer to SurfaceFlinger status_t addClientLayer(const sp& client, const sp& handle, - const sp& gbc, const sp& lbc, - const wp& parentLayer, bool addToRoot, + const sp& lbc, const wp& parentLayer, bool addToRoot, uint32_t* outTransformHint); // Traverse through all the layers and compute and cache its bounds. @@ -1115,16 +1108,12 @@ private: float mGlobalSaturationFactor = 1.0f; mat4 mClientColorMatrix; - // Can't be unordered_set because wp<> isn't hashable - std::set> mGraphicBufferProducerList; size_t mMaxGraphicBufferProducerListSize = ISurfaceComposer::MAX_LAYERS; // If there are more GraphicBufferProducers tracked by SurfaceFlinger than // this threshold, then begin logging. size_t mGraphicBufferProducerListSizeLogThreshold = static_cast(0.95 * static_cast(MAX_LAYERS)); - void removeGraphicBufferProducerAsync(const wp&); - // protected by mStateLock (but we could use another lock) bool mLayersRemoved = false; bool mLayersAdded = false; @@ -1339,19 +1328,12 @@ private: GUARDED_BY(mStateLock); mutable Mutex mCreatedLayersLock; struct LayerCreatedState { - LayerCreatedState(const wp& layer, const wp parent, - const wp& producer, bool addToRoot) - : layer(layer), - initialParent(parent), - initialProducer(producer), - addToRoot(addToRoot) {} + LayerCreatedState(const wp& layer, const wp parent, bool addToRoot) + : layer(layer), initialParent(parent), addToRoot(addToRoot) {} wp layer; // Indicates the initial parent of the created layer, only used for creating layer in // SurfaceFlinger. If nullptr, it may add the created layer into the current root layers. wp initialParent; - // Indicates the initial graphic buffer producer of the created layer, only used for - // creating layer in SurfaceFlinger. - wp initialProducer; // Indicates whether the layer getting created should be added at root if there's no parent // and has permission ACCESS_SURFACE_FLINGER. If set to false and no parent, the layer will // be added offscreen. @@ -1362,7 +1344,7 @@ private: // thread. std::unordered_map> mCreatedLayers; void setLayerCreatedState(const sp& handle, const wp& layer, - const wp parent, const wp& producer, bool addToRoot); + const wp parent, bool addToRoot); auto getLayerCreatedState(const sp& handle); sp handleLayerCreatedLocked(const sp& handle) REQUIRES(mStateLock); diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index 2082c42001..28e8b8c78b 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -754,9 +754,7 @@ void SurfaceInterceptorTest::assertAllUpdatesFound(const Trace& trace) { } bool SurfaceInterceptorTest::surfaceCreationFound(const Increment& increment, bool foundSurface) { - bool isMatch(increment.surface_creation().name() == getUniqueName(LAYER_NAME, increment) && - increment.surface_creation().w() == SIZE_UPDATE && - increment.surface_creation().h() == SIZE_UPDATE); + bool isMatch(increment.surface_creation().name() == getUniqueName(LAYER_NAME, increment)); if (isMatch && !foundSurface) { foundSurface = true; } else if (isMatch && foundSurface) { diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 40ef6e702d..52d8c35ede 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -535,6 +535,7 @@ struct BaseLayerProperties { static void setupLatchedBuffer(CompositionTest* test, sp layer) { // TODO: Eliminate the complexity of actually creating a buffer + layer->setSizeForTest(LayerProperties::WIDTH, LayerProperties::HEIGHT); status_t err = layer->setDefaultBufferProperties(LayerProperties::WIDTH, LayerProperties::HEIGHT, LayerProperties::FORMAT); @@ -901,7 +902,6 @@ struct EffectLayerVariant : public BaseLayerVariant { FlingerLayerType layer = Base::template createLayerWithFactory(test, [test]() { return new EffectLayer( LayerCreationArgs(test->mFlinger.flinger(), sp(), "test-layer", - LayerProperties::WIDTH, LayerProperties::HEIGHT, LayerProperties::LAYER_FLAGS, LayerMetadata())); }); @@ -940,7 +940,6 @@ struct BufferLayerVariant : public BaseLayerVariant { FlingerLayerType layer = Base::template createLayerWithFactory(test, [test]() { LayerCreationArgs args(test->mFlinger.flinger(), sp(), "test-layer", - LayerProperties::WIDTH, LayerProperties::HEIGHT, LayerProperties::LAYER_FLAGS, LayerMetadata()); args.textureName = test->mFlinger.mutableTexturePool().back(); return new BufferQueueLayer(args); @@ -952,7 +951,6 @@ struct BufferLayerVariant : public BaseLayerVariant { } static void cleanupInjectedLayers(CompositionTest* test) { - EXPECT_CALL(*test->mMessageQueue, postMessage(_)).Times(1); Base::cleanupInjectedLayers(test); } @@ -990,7 +988,6 @@ struct ContainerLayerVariant : public BaseLayerVariant { static FlingerLayerType createLayer(CompositionTest* test) { LayerCreationArgs args(test->mFlinger.flinger(), sp(), "test-container-layer", - LayerProperties::WIDTH, LayerProperties::HEIGHT, LayerProperties::LAYER_FLAGS, LayerMetadata()); FlingerLayerType layer = new ContainerLayer(args); Base::template initLayerDrawingStateAndComputeBounds(test, layer); diff --git a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp index 010c675574..cd2fc7426e 100644 --- a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp +++ b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp @@ -114,8 +114,7 @@ FpsReporterTest::~FpsReporterTest() { sp FpsReporterTest::createBufferStateLayer(LayerMetadata metadata = {}) { sp client; - LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", WIDTH, HEIGHT, - LAYER_FLAGS, metadata); + LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS, metadata); return new BufferStateLayer(args); } diff --git a/services/surfaceflinger/tests/unittests/GameModeTest.cpp b/services/surfaceflinger/tests/unittests/GameModeTest.cpp index 3fa1a2c2f5..d6459429fb 100644 --- a/services/surfaceflinger/tests/unittests/GameModeTest.cpp +++ b/services/surfaceflinger/tests/unittests/GameModeTest.cpp @@ -53,7 +53,7 @@ public: sp createBufferStateLayer() { sp client; - LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 100, 100, 0, + LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 0, LayerMetadata()); return new BufferStateLayer(args); } diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp index e388a6f40f..1e6e3361b2 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp @@ -91,15 +91,14 @@ RefreshRateSelectionTest::~RefreshRateSelectionTest() { sp RefreshRateSelectionTest::createBufferStateLayer() { sp client; - LayerCreationArgs args(mFlinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT, - LAYER_FLAGS, LayerMetadata()); + LayerCreationArgs args(mFlinger.flinger(), client, "buffer-queue-layer", LAYER_FLAGS, + LayerMetadata()); return new BufferStateLayer(args); } sp RefreshRateSelectionTest::createEffectLayer() { sp client; - LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS, - LayerMetadata()); + LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", LAYER_FLAGS, LayerMetadata()); return new EffectLayer(args); } diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index d0211780ab..360f9c684f 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -70,8 +70,8 @@ public: std::string name() override { return "BufferStateLayer"; } sp createLayer(TestableSurfaceFlinger& flinger) override { sp client; - LayerCreationArgs args(flinger.flinger(), client, "buffer-state-layer", WIDTH, HEIGHT, - LAYER_FLAGS, LayerMetadata()); + LayerCreationArgs args(flinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS, + LayerMetadata()); return new BufferStateLayer(args); } }; @@ -81,7 +81,7 @@ public: std::string name() override { return "EffectLayer"; } sp createLayer(TestableSurfaceFlinger& flinger) override { sp client; - LayerCreationArgs args(flinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS, + LayerCreationArgs args(flinger.flinger(), client, "color-layer", LAYER_FLAGS, LayerMetadata()); return new EffectLayer(args); } diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp index bd6a7805ec..deeb785bb9 100644 --- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp @@ -57,7 +57,7 @@ public: sp createBufferStateLayer() { sp client; - LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 100, 100, 0, + LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 0, LayerMetadata()); return new BufferStateLayer(args); } diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp index bf69704210..704340deac 100644 --- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp @@ -57,7 +57,7 @@ public: sp createBufferStateLayer() { sp client; - LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 100, 100, 0, + LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 0, LayerMetadata()); return new BufferStateLayer(args); } diff --git a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp index e4f74694f7..ade4fbb850 100644 --- a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp +++ b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp @@ -100,8 +100,7 @@ TunnelModeEnabledReporterTest::~TunnelModeEnabledReporterTest() { sp TunnelModeEnabledReporterTest::createBufferStateLayer( LayerMetadata metadata = {}) { sp client; - LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", WIDTH, HEIGHT, - LAYER_FLAGS, metadata); + LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS, metadata); return new BufferStateLayer(args); } diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h index ba2e4db0fa..8b48e1c16d 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h +++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h @@ -25,7 +25,7 @@ namespace android::mock { class MockLayer : public Layer { public: MockLayer(SurfaceFlinger* flinger, std::string name) - : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 800, 600, 0, {})) {} + : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) {} explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {} MOCK_CONST_METHOD0(getType, const char*()); -- cgit v1.2.3-59-g8ed1b From 00b9013d323caceec2528326809bf65d50c39c72 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 5 Nov 2021 14:03:40 -0700 Subject: SF: Simplify layer tracing As preparation to support transaction tracing, do the following: 1. refactor the ring buffer code so it can be reused 2. remove layer async tracing since we will use transaction tracing for always on tracing Test: presubmit Test: capture sf trace via bugreport Bug: 200284593 Change-Id: I28388c6db27a420c078e1cc33b0b378c55c6c5d6 --- services/surfaceflinger/Android.bp | 2 +- services/surfaceflinger/Layer.cpp | 163 +++++++------- services/surfaceflinger/Layer.h | 4 +- services/surfaceflinger/SurfaceFlinger.cpp | 44 ++-- services/surfaceflinger/SurfaceFlinger.h | 11 +- services/surfaceflinger/SurfaceTracing.cpp | 264 ----------------------- services/surfaceflinger/SurfaceTracing.h | 164 -------------- services/surfaceflinger/Tracing/LayerTracing.cpp | 130 +++++++++++ services/surfaceflinger/Tracing/LayerTracing.h | 77 +++++++ services/surfaceflinger/Tracing/RingBuffer.h | 112 ++++++++++ 10 files changed, 420 insertions(+), 551 deletions(-) delete mode 100644 services/surfaceflinger/SurfaceTracing.cpp delete mode 100644 services/surfaceflinger/SurfaceTracing.h create mode 100644 services/surfaceflinger/Tracing/LayerTracing.cpp create mode 100644 services/surfaceflinger/Tracing/LayerTracing.h create mode 100644 services/surfaceflinger/Tracing/RingBuffer.h diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 56b8374eb0..4e29172609 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -200,7 +200,7 @@ filegroup { "SurfaceFlinger.cpp", "SurfaceFlingerDefaultFactory.cpp", "SurfaceInterceptor.cpp", - "SurfaceTracing.cpp", + "Tracing/LayerTracing.cpp", "Tracing/TransactionProtoParser.cpp", "TransactionCallbackInvoker.cpp", "TunnelModeEnabledReporter.cpp", diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 3d189d681b..f5c5b4a70a 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2005,7 +2005,7 @@ LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags, writeToProtoDrawingState(layerProto, traceFlags, display); writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags); - if (traceFlags & SurfaceTracing::TRACE_COMPOSITION) { + if (traceFlags & LayerTracing::TRACE_COMPOSITION) { // Only populate for the primary display. if (display) { const Hwc2::IComposerClient::Composition compositionType = getCompositionType(*display); @@ -2023,43 +2023,38 @@ LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags, void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, const DisplayDevice* display) { const ui::Transform transform = getTransform(); + auto buffer = getBuffer(); + if (buffer != nullptr) { + LayerProtoHelper::writeToProto(buffer, + [&]() { return layerInfo->mutable_active_buffer(); }); + LayerProtoHelper::writeToProtoDeprecated(ui::Transform(getBufferTransform()), + layerInfo->mutable_buffer_transform()); + } + layerInfo->set_invalidate(contentDirty); + layerInfo->set_is_protected(isProtected()); + layerInfo->set_dataspace(dataspaceDetails(static_cast(getDataSpace()))); + layerInfo->set_queued_frames(getQueuedFrameCount()); + layerInfo->set_refresh_pending(isBufferLatched()); + layerInfo->set_curr_frame(mCurrentFrameNumber); + layerInfo->set_effective_scaling_mode(getEffectiveScalingMode()); + + layerInfo->set_requested_corner_radius(getDrawingState().cornerRadius); + layerInfo->set_corner_radius(getRoundedCornerState().radius); + layerInfo->set_background_blur_radius(getBackgroundBlurRadius()); + layerInfo->set_is_trusted_overlay(isTrustedOverlay()); + LayerProtoHelper::writeToProtoDeprecated(transform, layerInfo->mutable_transform()); + LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(), + [&]() { return layerInfo->mutable_position(); }); + LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); }); + if (traceFlags & LayerTracing::TRACE_COMPOSITION) { + LayerProtoHelper::writeToProto(getVisibleRegion(display), + [&]() { return layerInfo->mutable_visible_region(); }); + } + LayerProtoHelper::writeToProto(surfaceDamageRegion, + [&]() { return layerInfo->mutable_damage_region(); }); - if (traceFlags & SurfaceTracing::TRACE_CRITICAL) { - - auto buffer = getBuffer(); - if (buffer != nullptr) { - LayerProtoHelper::writeToProto(buffer, - [&]() { return layerInfo->mutable_active_buffer(); }); - LayerProtoHelper::writeToProtoDeprecated(ui::Transform(getBufferTransform()), - layerInfo->mutable_buffer_transform()); - } - layerInfo->set_invalidate(contentDirty); - layerInfo->set_is_protected(isProtected()); - layerInfo->set_dataspace(dataspaceDetails(static_cast(getDataSpace()))); - layerInfo->set_queued_frames(getQueuedFrameCount()); - layerInfo->set_refresh_pending(isBufferLatched()); - layerInfo->set_curr_frame(mCurrentFrameNumber); - layerInfo->set_effective_scaling_mode(getEffectiveScalingMode()); - - layerInfo->set_requested_corner_radius(getDrawingState().cornerRadius); - layerInfo->set_corner_radius(getRoundedCornerState().radius); - layerInfo->set_background_blur_radius(getBackgroundBlurRadius()); - layerInfo->set_is_trusted_overlay(isTrustedOverlay()); - LayerProtoHelper::writeToProtoDeprecated(transform, layerInfo->mutable_transform()); - LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(), - [&]() { return layerInfo->mutable_position(); }); - LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); }); - if (traceFlags & SurfaceTracing::TRACE_COMPOSITION) { - LayerProtoHelper::writeToProto(getVisibleRegion(display), - [&]() { return layerInfo->mutable_visible_region(); }); - } - LayerProtoHelper::writeToProto(surfaceDamageRegion, - [&]() { return layerInfo->mutable_damage_region(); }); - - if (hasColorTransform()) { - LayerProtoHelper::writeToProto(getColorTransform(), - layerInfo->mutable_color_transform()); - } + if (hasColorTransform()) { + LayerProtoHelper::writeToProto(getColorTransform(), layerInfo->mutable_color_transform()); } LayerProtoHelper::writeToProto(mSourceBounds, @@ -2079,70 +2074,66 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet ui::Transform requestedTransform = state.transform; - if (traceFlags & SurfaceTracing::TRACE_CRITICAL) { - layerInfo->set_id(sequence); - layerInfo->set_name(getName().c_str()); - layerInfo->set_type(getType()); + layerInfo->set_id(sequence); + layerInfo->set_name(getName().c_str()); + layerInfo->set_type(getType()); - for (const auto& child : children) { - layerInfo->add_children(child->sequence); - } + for (const auto& child : children) { + layerInfo->add_children(child->sequence); + } - for (const wp& weakRelative : state.zOrderRelatives) { - sp strongRelative = weakRelative.promote(); - if (strongRelative != nullptr) { - layerInfo->add_relatives(strongRelative->sequence); - } + for (const wp& weakRelative : state.zOrderRelatives) { + sp strongRelative = weakRelative.promote(); + if (strongRelative != nullptr) { + layerInfo->add_relatives(strongRelative->sequence); } + } - LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy, - [&]() { return layerInfo->mutable_transparent_region(); }); - - layerInfo->set_layer_stack(getLayerStack().id); - layerInfo->set_z(state.z); + LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy, + [&]() { return layerInfo->mutable_transparent_region(); }); - LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(), - [&]() { - return layerInfo->mutable_requested_position(); - }); + layerInfo->set_layer_stack(getLayerStack().id); + layerInfo->set_z(state.z); - LayerProtoHelper::writeSizeToProto(state.width, state.height, - [&]() { return layerInfo->mutable_size(); }); + LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(), [&]() { + return layerInfo->mutable_requested_position(); + }); - LayerProtoHelper::writeToProto(state.crop, [&]() { return layerInfo->mutable_crop(); }); + LayerProtoHelper::writeSizeToProto(state.width, state.height, + [&]() { return layerInfo->mutable_size(); }); - layerInfo->set_is_opaque(isOpaque(state)); + LayerProtoHelper::writeToProto(state.crop, [&]() { return layerInfo->mutable_crop(); }); + layerInfo->set_is_opaque(isOpaque(state)); - layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat())); - LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); }); - LayerProtoHelper::writeToProto(state.color, - [&]() { return layerInfo->mutable_requested_color(); }); - layerInfo->set_flags(state.flags); + layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat())); + LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); }); + LayerProtoHelper::writeToProto(state.color, + [&]() { return layerInfo->mutable_requested_color(); }); + layerInfo->set_flags(state.flags); - LayerProtoHelper::writeToProtoDeprecated(requestedTransform, - layerInfo->mutable_requested_transform()); + LayerProtoHelper::writeToProtoDeprecated(requestedTransform, + layerInfo->mutable_requested_transform()); - auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote(); - if (parent != nullptr) { - layerInfo->set_parent(parent->sequence); - } else { - layerInfo->set_parent(-1); - } + auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote(); + if (parent != nullptr) { + layerInfo->set_parent(parent->sequence); + } else { + layerInfo->set_parent(-1); + } - auto zOrderRelativeOf = state.zOrderRelativeOf.promote(); - if (zOrderRelativeOf != nullptr) { - layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence); - } else { - layerInfo->set_z_order_relative_of(-1); - } + auto zOrderRelativeOf = state.zOrderRelativeOf.promote(); + if (zOrderRelativeOf != nullptr) { + layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence); + } else { + layerInfo->set_z_order_relative_of(-1); + } - layerInfo->set_is_relative_of(state.isRelativeOf); + layerInfo->set_is_relative_of(state.isRelativeOf); - layerInfo->set_owner_uid(mOwnerUid); - } + layerInfo->set_owner_uid(mOwnerUid); - if (traceFlags & SurfaceTracing::TRACE_INPUT) { + if (traceFlags & LayerTracing::TRACE_INPUT) { WindowInfo info; if (useDrawing) { info = fillInputInfo(ui::Transform(), /* displayIsSecure */ true); @@ -2154,7 +2145,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet [&]() { return layerInfo->mutable_input_window_info(); }); } - if (traceFlags & SurfaceTracing::TRACE_EXTRA) { + if (traceFlags & LayerTracing::TRACE_EXTRA) { auto protoMap = layerInfo->mutable_metadata(); for (const auto& entry : state.metadata.mMap) { (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend()); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 3da07e824d..5af8dda2fc 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -57,7 +57,7 @@ #include "Scheduler/LayerInfo.h" #include "Scheduler/Seamlessness.h" #include "SurfaceFlinger.h" -#include "SurfaceTracing.h" +#include "Tracing/LayerTracing.h" #include "TransactionCallbackInvoker.h" using namespace android::surfaceflinger; @@ -691,7 +691,7 @@ public: // external mStateLock. If writing drawing state, this function should be called on the // main or tracing thread. void writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet, - uint32_t traceFlags = SurfaceTracing::TRACE_ALL); + uint32_t traceFlags = LayerTracing::TRACE_ALL); gui::WindowInfo::Type getWindowType() const { return mWindowType; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5a6a8ce05a..a990e6b893 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1948,7 +1948,7 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected } if (mTracingEnabledChanged) { - mTracingEnabled = mTracing.isEnabled(); + mTracingEnabled = mLayerTracing.isEnabled(); mTracingEnabledChanged = false; } @@ -1962,24 +1962,12 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected // Composite if transactions were committed, or if requested by HWC. bool mustComposite = mMustComposite.exchange(false); { - mTracePostComposition = mTracing.flagIsSet(SurfaceTracing::TRACE_COMPOSITION) || - mTracing.flagIsSet(SurfaceTracing::TRACE_SYNC) || - mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS); - const bool tracePreComposition = mTracingEnabled && !mTracePostComposition; - ConditionalLockGuard lock(mTracingLock, tracePreComposition); - mFrameTimeline->setSfWakeUp(vsyncId, frameTime, Fps::fromPeriodNsecs(stats.vsyncPeriod)); mustComposite |= flushAndCommitTransactions(); mustComposite |= latchBuffers(); updateLayerGeometry(); - - if (tracePreComposition) { - if (mVisibleRegionsDirty) { - mTracing.notifyLocked("visibleRegionsDirty"); - } - } } // Layers need to get updated (in the previous line) before we can use them for @@ -2112,12 +2100,12 @@ void SurfaceFlinger::composite(nsecs_t frameTime) { modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition); mLayersWithQueuedFrames.clear(); - if (mTracingEnabled && mTracePostComposition) { - // This may block if SurfaceTracing is running in sync mode. + if (mTracingEnabled) { + // This will block and should only be used for debugging. if (mVisibleRegionsDirty) { - mTracing.notify("visibleRegionsDirty"); - } else if (mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS)) { - mTracing.notify("bufferLatched"); + mLayerTracing.notify("visibleRegionsDirty"); + } else if (mLayerTracing.flagIsSet(LayerTracing::TRACE_BUFFERS)) { + mLayerTracing.notify("bufferLatched"); } } @@ -4647,7 +4635,7 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { } if (dumpLayers) { - LayersTraceFileProto traceFileProto = SurfaceTracing::createLayersTraceFileProto(); + LayersTraceFileProto traceFileProto = mLayerTracing.createTraceFileProto(); LayersTraceProto* layersTrace = traceFileProto.add_entry(); LayersProto layersProto = dumpProtoFromMainThread(); layersTrace->mutable_layers()->Swap(&layersProto); @@ -4669,8 +4657,8 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { } status_t SurfaceFlinger::dumpCritical(int fd, const DumpArgs&, bool asProto) { - if (asProto && mTracing.isEnabled()) { - mTracing.writeToFile(); + if (asProto && mLayerTracing.isEnabled()) { + mLayerTracing.writeToFile(); } return doDump(fd, DumpArgs(), asProto); @@ -5066,7 +5054,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co /* * Tracing state */ - mTracing.dump(result); + mLayerTracing.dump(result); result.append("\n"); /* @@ -5493,20 +5481,20 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r bool tracingEnabledChanged; if (n) { ALOGD("LayerTracing enabled"); - tracingEnabledChanged = mTracing.enable(); + tracingEnabledChanged = mLayerTracing.enable(); if (tracingEnabledChanged) { - schedule([&]() MAIN_THREAD { mTracing.notify("start"); }).wait(); + schedule([&]() MAIN_THREAD { mLayerTracing.notify("start"); }).wait(); } } else { ALOGD("LayerTracing disabled"); - tracingEnabledChanged = mTracing.disable(); + tracingEnabledChanged = mLayerTracing.disable(); } mTracingEnabledChanged = tracingEnabledChanged; reply->writeInt32(NO_ERROR); return NO_ERROR; } case 1026: { // Get layer tracing status - reply->writeBool(mTracing.isEnabled()); + reply->writeBool(mLayerTracing.isEnabled()); return NO_ERROR; } // Is a DisplayColorSetting supported? @@ -5547,7 +5535,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } ALOGD("Updating trace buffer to %d KB", n); - mTracing.setBufferSize(n * 1024); + mLayerTracing.setBufferSize(n * 1024); reply->writeInt32(NO_ERROR); return NO_ERROR; } @@ -5592,7 +5580,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r case 1033: { n = data.readUint32(); ALOGD("Updating trace flags to 0x%x", n); - mTracing.setTraceFlags(n); + mLayerTracing.setTraceFlags(n); reply->writeInt32(NO_ERROR); return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b432f246c0..e3bcde2070 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -62,8 +62,8 @@ #include "Scheduler/Scheduler.h" #include "Scheduler/VsyncModulator.h" #include "SurfaceFlingerFactory.h" -#include "SurfaceTracing.h" #include "TracedOrdinal.h" +#include "Tracing/LayerTracing.h" #include "TransactionCallbackInvoker.h" #include "TransactionState.h" @@ -353,7 +353,7 @@ private: friend class MonitoredProducer; friend class RefreshRateOverlay; friend class RegionSamplingThread; - friend class SurfaceTracing; + friend class LayerTracing; // For unit tests friend class TestableSurfaceFlinger; @@ -1042,12 +1042,12 @@ private: void dumpWideColorInfo(std::string& result) const REQUIRES(mStateLock); LayersProto dumpDrawingStateProto(uint32_t traceFlags) const; void dumpOffscreenLayersProto(LayersProto& layersProto, - uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; + uint32_t traceFlags = LayerTracing::TRACE_ALL) const; void dumpDisplayProto(LayersTraceProto& layersTraceProto) const; // Dumps state from HW Composer void dumpHwc(std::string& result) const; - LayersProto dumpProtoFromMainThread(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) + LayersProto dumpProtoFromMainThread(uint32_t traceFlags = LayerTracing::TRACE_ALL) EXCLUDES(mStateLock); void dumpOffscreenLayers(std::string& result) EXCLUDES(mStateLock); void dumpPlannerInfo(const DumpArgs& args, std::string& result) const REQUIRES(mStateLock); @@ -1190,10 +1190,9 @@ private: bool mPropagateBackpressureClientComposition = false; sp mInterceptor; - SurfaceTracing mTracing{*this}; + LayerTracing mLayerTracing{*this}; std::mutex mTracingLock; bool mTracingEnabled = false; - bool mTracePostComposition = false; std::atomic mTracingEnabledChanged = false; const std::shared_ptr mTimeStats; diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp deleted file mode 100644 index 596373732f..0000000000 --- a/services/surfaceflinger/SurfaceTracing.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#undef LOG_TAG -#define LOG_TAG "SurfaceTracing" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "SurfaceTracing.h" -#include - -#include -#include -#include -#include -#include - -namespace android { - -SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger) : mFlinger(flinger) {} - -bool SurfaceTracing::enable() { - std::scoped_lock lock(mTraceLock); - if (mEnabled) { - return false; - } - - if (flagIsSet(TRACE_SYNC)) { - runner = std::make_unique(mFlinger, mConfig); - } else { - runner = std::make_unique(mFlinger, mConfig, - mFlinger.mTracingLock); - } - mEnabled = true; - return true; -} - -bool SurfaceTracing::disable() { - std::scoped_lock lock(mTraceLock); - if (!mEnabled) { - return false; - } - mEnabled = false; - runner->stop(); - return true; -} - -bool SurfaceTracing::isEnabled() const { - std::scoped_lock lock(mTraceLock); - return mEnabled; -} - -status_t SurfaceTracing::writeToFile() { - std::scoped_lock lock(mTraceLock); - if (!mEnabled) { - return STATUS_OK; - } - return runner->writeToFile(); -} - -void SurfaceTracing::notify(const char* where) { - std::scoped_lock lock(mTraceLock); - if (mEnabled) { - runner->notify(where); - } -} - -void SurfaceTracing::notifyLocked(const char* where) { - std::scoped_lock lock(mTraceLock); - if (mEnabled) { - runner->notifyLocked(where); - } -} - -void SurfaceTracing::dump(std::string& result) const { - std::scoped_lock lock(mTraceLock); - base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled"); - if (mEnabled) { - runner->dump(result); - } -} - -void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) { - // use the swap trick to make sure memory is released - std::queue().swap(mStorage); - mSizeInBytes = newSize; - mUsedInBytes = 0U; -} - -void SurfaceTracing::LayersTraceBuffer::emplace(LayersTraceProto&& proto) { - size_t protoSize = static_cast(proto.ByteSize()); - while (mUsedInBytes + protoSize > mSizeInBytes) { - if (mStorage.empty()) { - return; - } - mUsedInBytes -= static_cast(mStorage.front().ByteSize()); - mStorage.pop(); - } - mUsedInBytes += protoSize; - mStorage.emplace(); - mStorage.back().Swap(&proto); -} - -void SurfaceTracing::LayersTraceBuffer::flush(LayersTraceFileProto* fileProto) { - fileProto->mutable_entry()->Reserve(static_cast(mStorage.size())); - - while (!mStorage.empty()) { - auto entry = fileProto->add_entry(); - entry->Swap(&mStorage.front()); - mStorage.pop(); - } -} - -SurfaceTracing::Runner::Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config) - : mFlinger(flinger), mConfig(config) { - mBuffer.setSize(mConfig.bufferSize); -} - -void SurfaceTracing::Runner::notify(const char* where) { - LayersTraceProto entry = traceLayers(where); - mBuffer.emplace(std::move(entry)); -} - -status_t SurfaceTracing::Runner::stop() { - return writeToFile(); -} - -LayersTraceFileProto SurfaceTracing::createLayersTraceFileProto() { - LayersTraceFileProto fileProto; - fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 | - LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L); - return fileProto; -} - -status_t SurfaceTracing::Runner::writeToFile() { - ATRACE_CALL(); - - LayersTraceFileProto fileProto = createLayersTraceFileProto(); - std::string output; - - mBuffer.flush(&fileProto); - mBuffer.reset(mConfig.bufferSize); - - if (!fileProto.SerializeToString(&output)) { - ALOGE("Could not save the proto file! Permission denied"); - return PERMISSION_DENIED; - } - - // -rw-r--r-- - const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; - if (!android::base::WriteStringToFile(output, DEFAULT_FILE_NAME, mode, getuid(), getgid(), - true)) { - ALOGE("Could not save the proto file! There are missing fields"); - return PERMISSION_DENIED; - } - - return NO_ERROR; -} - -LayersTraceProto SurfaceTracing::Runner::traceLayers(const char* where) { - ATRACE_CALL(); - - LayersTraceProto entry; - entry.set_elapsed_realtime_nanos(elapsedRealtimeNano()); - entry.set_where(where); - LayersProto layers(mFlinger.dumpDrawingStateProto(mConfig.flags)); - - if (flagIsSet(SurfaceTracing::TRACE_EXTRA)) { - mFlinger.dumpOffscreenLayersProto(layers); - } - entry.mutable_layers()->Swap(&layers); - - if (flagIsSet(SurfaceTracing::TRACE_HWC)) { - std::string hwcDump; - mFlinger.dumpHwc(hwcDump); - entry.set_hwc_blob(hwcDump); - } - if (!flagIsSet(SurfaceTracing::TRACE_COMPOSITION)) { - entry.set_excludes_composition_state(true); - } - entry.set_missed_entries(mMissedTraceEntries); - mFlinger.dumpDisplayProto(entry); - return entry; -} - -void SurfaceTracing::Runner::dump(std::string& result) const { - base::StringAppendF(&result, " number of entries: %zu (%.2fMB / %.2fMB)\n", - mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB), - float(mBuffer.size()) / float(1_MB)); -} - -SurfaceTracing::AsyncRunner::AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config, - std::mutex& sfLock) - : SurfaceTracing::Runner(flinger, config), mSfLock(sfLock) { - mEnabled = true; - mThread = std::thread(&AsyncRunner::loop, this); -} - -void SurfaceTracing::AsyncRunner::loop() { - while (mEnabled) { - LayersTraceProto entry; - bool entryAdded = traceWhenNotified(&entry); - if (entryAdded) { - mBuffer.emplace(std::move(entry)); - } - if (mWriteToFile) { - Runner::writeToFile(); - mWriteToFile = false; - } - } -} - -bool SurfaceTracing::AsyncRunner::traceWhenNotified(LayersTraceProto* outProto) { - std::unique_lock lock(mSfLock); - mCanStartTrace.wait(lock); - if (!mAddEntry) { - return false; - } - *outProto = traceLayers(mWhere); - mAddEntry = false; - mMissedTraceEntries = 0; - return true; -} - -void SurfaceTracing::AsyncRunner::notify(const char* where) { - std::scoped_lock lock(mSfLock); - notifyLocked(where); -} - -void SurfaceTracing::AsyncRunner::notifyLocked(const char* where) { - mWhere = where; - if (mAddEntry) { - mMissedTraceEntries++; - } - mAddEntry = true; - mCanStartTrace.notify_one(); -} - -status_t SurfaceTracing::AsyncRunner::writeToFile() { - mWriteToFile = true; - mCanStartTrace.notify_one(); - return STATUS_OK; -} - -status_t SurfaceTracing::AsyncRunner::stop() { - mEnabled = false; - mCanStartTrace.notify_one(); - mThread.join(); - return Runner::writeToFile(); -} - -} // namespace android diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h deleted file mode 100644 index 97adb20c63..0000000000 --- a/services/surfaceflinger/SurfaceTracing.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2017 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 -#include -#include -#include - -#include -#include -#include -#include -#include - -using namespace android::surfaceflinger; - -namespace android { - -class SurfaceFlinger; -constexpr auto operator""_MB(unsigned long long const num) { - return num * 1024 * 1024; -} -/* - * SurfaceTracing records layer states during surface flinging. Manages tracing state and - * configuration. - */ -class SurfaceTracing { -public: - SurfaceTracing(SurfaceFlinger& flinger); - bool enable(); - bool disable(); - status_t writeToFile(); - bool isEnabled() const; - /* - * Adds a trace entry, must be called from the drawing thread or while holding the - * SurfaceFlinger tracing lock. - */ - void notify(const char* where); - /* - * Adds a trace entry, called while holding the SurfaceFlinger tracing lock. - */ - void notifyLocked(const char* where) /* REQUIRES(mSfLock) */; - - void setBufferSize(size_t bufferSizeInBytes) { mConfig.bufferSize = bufferSizeInBytes; } - void dump(std::string& result) const; - - enum : uint32_t { - TRACE_CRITICAL = 1 << 0, - TRACE_INPUT = 1 << 1, - TRACE_COMPOSITION = 1 << 2, - TRACE_EXTRA = 1 << 3, - TRACE_HWC = 1 << 4, - // Add non-geometry composition changes to the trace. - TRACE_BUFFERS = 1 << 5, - // Add entries from the drawing thread post composition. - TRACE_SYNC = 1 << 6, - TRACE_ALL = TRACE_CRITICAL | TRACE_INPUT | TRACE_COMPOSITION | TRACE_EXTRA, - }; - void setTraceFlags(uint32_t flags) { mConfig.flags = flags; } - bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; } - static LayersTraceFileProto createLayersTraceFileProto(); - -private: - class Runner; - static constexpr auto DEFAULT_BUFFER_SIZE = 20_MB; - static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.winscope"; - - SurfaceFlinger& mFlinger; - mutable std::mutex mTraceLock; - bool mEnabled GUARDED_BY(mTraceLock) = false; - std::unique_ptr runner GUARDED_BY(mTraceLock); - - struct Config { - uint32_t flags = TRACE_CRITICAL | TRACE_INPUT | TRACE_SYNC; - size_t bufferSize = DEFAULT_BUFFER_SIZE; - } mConfig; - - /* - * ring buffer. - */ - class LayersTraceBuffer { - public: - size_t size() const { return mSizeInBytes; } - size_t used() const { return mUsedInBytes; } - size_t frameCount() const { return mStorage.size(); } - - void setSize(size_t newSize) { mSizeInBytes = newSize; } - void reset(size_t newSize); - void emplace(LayersTraceProto&& proto); - void flush(LayersTraceFileProto* fileProto); - - private: - size_t mUsedInBytes = 0U; - size_t mSizeInBytes = DEFAULT_BUFFER_SIZE; - std::queue mStorage; - }; - - /* - * Implements a synchronous way of adding trace entries. This must be called - * from the drawing thread. - */ - class Runner { - public: - Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config); - virtual ~Runner() = default; - virtual status_t stop(); - virtual status_t writeToFile(); - virtual void notify(const char* where); - /* Cannot be called with a synchronous runner. */ - virtual void notifyLocked(const char* /* where */) {} - void dump(std::string& result) const; - - protected: - bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; } - SurfaceFlinger& mFlinger; - SurfaceTracing::Config mConfig; - SurfaceTracing::LayersTraceBuffer mBuffer; - uint32_t mMissedTraceEntries = 0; - LayersTraceProto traceLayers(const char* where); - }; - - /* - * Implements asynchronous way to add trace entries called from a separate thread while holding - * the SurfaceFlinger tracing lock. Trace entries may be missed if the tracing thread is not - * scheduled in time. - */ - class AsyncRunner : public Runner { - public: - AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config, std::mutex& sfLock); - virtual ~AsyncRunner() = default; - status_t stop() override; - status_t writeToFile() override; - void notify(const char* where) override; - void notifyLocked(const char* where); - - private: - std::mutex& mSfLock; - std::condition_variable mCanStartTrace; - std::thread mThread; - const char* mWhere = ""; - bool mWriteToFile = false; - bool mEnabled = false; - bool mAddEntry = false; - void loop(); - bool traceWhenNotified(LayersTraceProto* outProto); - }; -}; - -} // namespace android diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp new file mode 100644 index 0000000000..84890eefd1 --- /dev/null +++ b/services/surfaceflinger/Tracing/LayerTracing.cpp @@ -0,0 +1,130 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef LOG_TAG +#define LOG_TAG "LayerTracing" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include +#include +#include +#include +#include + +#include "LayerTracing.h" +#include "RingBuffer.h" + +namespace android { + +LayerTracing::LayerTracing(SurfaceFlinger& flinger) : mFlinger(flinger) { + mBuffer = std::make_unique>(); +} + +LayerTracing::~LayerTracing() = default; + +bool LayerTracing::enable() { + std::scoped_lock lock(mTraceLock); + if (mEnabled) { + return false; + } + mBuffer->setSize(mBufferSizeInBytes); + mEnabled = true; + return true; +} + +bool LayerTracing::disable() { + std::scoped_lock lock(mTraceLock); + if (!mEnabled) { + return false; + } + mEnabled = false; + LayersTraceFileProto fileProto = createTraceFileProto(); + mBuffer->writeToFile(fileProto, FILE_NAME); + return true; +} + +bool LayerTracing::isEnabled() const { + std::scoped_lock lock(mTraceLock); + return mEnabled; +} + +status_t LayerTracing::writeToFile() { + std::scoped_lock lock(mTraceLock); + if (!mEnabled) { + return STATUS_OK; + } + LayersTraceFileProto fileProto = createTraceFileProto(); + return mBuffer->writeToFile(fileProto, FILE_NAME); +} + +void LayerTracing::setTraceFlags(uint32_t flags) { + std::scoped_lock lock(mTraceLock); + mFlags = flags; +} + +void LayerTracing::setBufferSize(size_t bufferSizeInBytes) { + std::scoped_lock lock(mTraceLock); + mBufferSizeInBytes = bufferSizeInBytes; +} + +bool LayerTracing::flagIsSet(uint32_t flags) const { + return (mFlags & flags) == flags; +} + +LayersTraceFileProto LayerTracing::createTraceFileProto() const { + LayersTraceFileProto fileProto; + fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 | + LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L); + return fileProto; +} + +void LayerTracing::dump(std::string& result) const { + std::scoped_lock lock(mTraceLock); + base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled"); + mBuffer->dump(result); +} + +void LayerTracing::notify(const char* where) { + ATRACE_CALL(); + std::scoped_lock lock(mTraceLock); + if (!mEnabled) { + return; + } + + ATRACE_CALL(); + LayersTraceProto entry; + entry.set_elapsed_realtime_nanos(elapsedRealtimeNano()); + entry.set_where(where); + LayersProto layers(mFlinger.dumpDrawingStateProto(mFlags)); + + if (flagIsSet(LayerTracing::TRACE_EXTRA)) { + mFlinger.dumpOffscreenLayersProto(layers); + } + entry.mutable_layers()->Swap(&layers); + + if (flagIsSet(LayerTracing::TRACE_HWC)) { + std::string hwcDump; + mFlinger.dumpHwc(hwcDump); + entry.set_hwc_blob(hwcDump); + } + if (!flagIsSet(LayerTracing::TRACE_COMPOSITION)) { + entry.set_excludes_composition_state(true); + } + mFlinger.dumpDisplayProto(entry); + mBuffer->emplace(std::move(entry)); +} + +} // namespace android diff --git a/services/surfaceflinger/Tracing/LayerTracing.h b/services/surfaceflinger/Tracing/LayerTracing.h new file mode 100644 index 0000000000..8ca3587dbc --- /dev/null +++ b/services/surfaceflinger/Tracing/LayerTracing.h @@ -0,0 +1,77 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +using namespace android::surfaceflinger; + +namespace android { + +template +class RingBuffer; + +class SurfaceFlinger; + +/* + * LayerTracing records layer states during surface flinging. Manages tracing state and + * configuration. + */ +class LayerTracing { +public: + LayerTracing(SurfaceFlinger& flinger); + ~LayerTracing(); + bool enable(); + bool disable(); + bool isEnabled() const; + status_t writeToFile(); + LayersTraceFileProto createTraceFileProto() const; + void notify(const char* where); + + enum : uint32_t { + TRACE_INPUT = 1 << 1, + TRACE_COMPOSITION = 1 << 2, + TRACE_EXTRA = 1 << 3, + TRACE_HWC = 1 << 4, + TRACE_BUFFERS = 1 << 5, + TRACE_ALL = TRACE_INPUT | TRACE_COMPOSITION | TRACE_EXTRA, + }; + void setTraceFlags(uint32_t flags); + bool flagIsSet(uint32_t flags) const; + void setBufferSize(size_t bufferSizeInBytes); + void dump(std::string&) const; + +private: + static constexpr auto FILE_NAME = "/data/misc/wmtrace/layers_trace.winscope"; + + SurfaceFlinger& mFlinger; + uint32_t mFlags = TRACE_INPUT; + mutable std::mutex mTraceLock; + bool mEnabled GUARDED_BY(mTraceLock) = false; + std::unique_ptr> mBuffer + GUARDED_BY(mTraceLock); + size_t mBufferSizeInBytes GUARDED_BY(mTraceLock) = 20 * 1024 * 1024; +}; + +} // namespace android diff --git a/services/surfaceflinger/Tracing/RingBuffer.h b/services/surfaceflinger/Tracing/RingBuffer.h new file mode 100644 index 0000000000..d0fb3f28fe --- /dev/null +++ b/services/surfaceflinger/Tracing/RingBuffer.h @@ -0,0 +1,112 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +namespace android { + +class SurfaceFlinger; + +template +class RingBuffer { +public: + size_t size() const { return mSizeInBytes; } + size_t used() const { return mUsedInBytes; } + size_t frameCount() const { return mStorage.size(); } + void setSize(size_t newSize) { mSizeInBytes = newSize; } + EntryProto& front() { return mStorage.front(); } + const EntryProto& front() const { return mStorage.front(); } + + void reset(size_t newSize) { + // use the swap trick to make sure memory is released + std::queue().swap(mStorage); + mSizeInBytes = newSize; + mUsedInBytes = 0U; + } + void flush(FileProto& fileProto) { + fileProto.mutable_entry()->Reserve(static_cast(mStorage.size())); + while (!mStorage.empty()) { + auto entry = fileProto.add_entry(); + entry->Swap(&mStorage.front()); + mStorage.pop(); + } + } + + status_t writeToFile(FileProto& fileProto, std::string filename) { + ATRACE_CALL(); + std::string output; + flush(fileProto); + reset(mSizeInBytes); + if (!fileProto.SerializeToString(&output)) { + ALOGE("Could not serialize proto."); + return UNKNOWN_ERROR; + } + + // -rw-r--r-- + const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + if (!android::base::WriteStringToFile(output, filename, mode, getuid(), getgid(), true)) { + ALOGE("Could not save the proto file."); + return PERMISSION_DENIED; + } + return NO_ERROR; + } + + std::vector emplace(EntryProto&& proto) { + std::vector replacedEntries; + size_t protoSize = static_cast(proto.ByteSize()); + while (mUsedInBytes + protoSize > mSizeInBytes) { + if (mStorage.empty()) { + return {}; + } + mUsedInBytes -= static_cast(mStorage.front().ByteSize()); + replacedEntries.emplace_back(mStorage.front()); + mStorage.pop(); + } + mUsedInBytes += protoSize; + mStorage.emplace(); + mStorage.back().Swap(&proto); + return replacedEntries; + } + + void dump(std::string& result) const { + std::chrono::milliseconds duration(0); + if (frameCount() > 0) { + duration = std::chrono::duration_cast( + std::chrono::nanoseconds(systemTime() - front().elapsed_realtime_nanos())); + } + const int64_t durationCount = duration.count(); + base::StringAppendF(&result, + " number of entries: %zu (%.2fMB / %.2fMB) duration: %" PRIi64 "ms\n", + frameCount(), float(used()) / 1024.f * 1024.f, + float(size()) / 1024.f * 1024.f, durationCount); + } + +private: + size_t mUsedInBytes = 0U; + size_t mSizeInBytes = 0U; + std::queue mStorage; +}; + +} // namespace android -- cgit v1.2.3-59-g8ed1b From 465b2967f33f18e5e584dc8d18ce451b4590b331 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 8 Oct 2021 16:22:21 -0700 Subject: Add libtonemap library libtonemap is a vendor-available static library which provides a single point where the definitions of tone mapping operations can be shared. This faciliates sharing tone mapping operations between system libraries and vendor libraries without making invasive changes to the framework. The canonical use-case for this library is matching the tone-mapping curves between DPU composition and GPU composition for the display. Although not done in this patch, this library may be linked into libhwui, for propagating the tone mapping operation into TextureView. The initial design for this library is to expose a Tonemapper class, which can return: 1. A shader string describing the tonemapper operation, which may be inserted into any other shader string. 2. A list of shader uniforms for binding to the final shader A later patch will allow for computing the tone mapping curve on the CPU, which is useful for unit testing, and optionally for generating a LUT without firing up the GPU. Bug: 200310159 Ignore-AOSP-First: new internal-only lib Test: libtonemap_test Change-Id: I7f1353e0f456ec5f371e31754b2965c9b44aa125 --- libs/renderengine/Android.bp | 6 +- libs/renderengine/benchmark/Android.bp | 8 +- libs/renderengine/skia/filters/LinearEffect.cpp | 198 +++------------- libs/renderengine/tests/Android.bp | 6 +- libs/tonemap/Android.bp | 37 +++ libs/tonemap/OWNERS | 4 + libs/tonemap/TEST_MAPPING | 10 + libs/tonemap/include/tonemap/tonemap.h | 103 +++++++++ libs/tonemap/tests/Android.bp | 38 +++ libs/tonemap/tests/tonemap_test.cpp | 76 ++++++ libs/tonemap/tonemap.cpp | 256 +++++++++++++++++++++ services/surfaceflinger/Android.bp | 1 + .../surfaceflinger/CompositionEngine/Android.bp | 1 + services/surfaceflinger/tests/unittests/Android.bp | 1 + 14 files changed, 579 insertions(+), 166 deletions(-) create mode 100644 libs/tonemap/Android.bp create mode 100644 libs/tonemap/OWNERS create mode 100644 libs/tonemap/TEST_MAPPING create mode 100644 libs/tonemap/include/tonemap/tonemap.h create mode 100644 libs/tonemap/tests/Android.bp create mode 100644 libs/tonemap/tests/tonemap_test.cpp create mode 100644 libs/tonemap/tonemap.cpp diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index a62d2b9f85..ecfaef8928 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -40,6 +40,10 @@ cc_defaults { "libui", "libutils", ], + + static_libs: [ + "libtonemap", + ], local_include_dirs: ["include"], export_include_dirs: ["include"], } @@ -97,7 +101,7 @@ filegroup { "skia/filters/GaussianBlurFilter.cpp", "skia/filters/KawaseBlurFilter.cpp", "skia/filters/LinearEffect.cpp", - "skia/filters/StretchShaderFactory.cpp" + "skia/filters/StretchShaderFactory.cpp", ], } diff --git a/libs/renderengine/benchmark/Android.bp b/libs/renderengine/benchmark/Android.bp index 5968399544..baa50544b7 100644 --- a/libs/renderengine/benchmark/Android.bp +++ b/libs/renderengine/benchmark/Android.bp @@ -23,7 +23,10 @@ package { cc_benchmark { name: "librenderengine_bench", - defaults: ["skia_deps", "surfaceflinger_defaults"], + defaults: [ + "skia_deps", + "surfaceflinger_defaults", + ], srcs: [ "main.cpp", "Codec.cpp", @@ -32,6 +35,7 @@ cc_benchmark { ], static_libs: [ "librenderengine", + "libtonemap", ], cflags: [ "-DLOG_TAG=\"RenderEngineBench\"", @@ -50,5 +54,5 @@ cc_benchmark { "libutils", ], - data: [ "resources/*"], + data: ["resources/*"], } diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp index 73dadef166..53136e40b7 100644 --- a/libs/renderengine/skia/filters/LinearEffect.cpp +++ b/libs/renderengine/skia/filters/LinearEffect.cpp @@ -19,6 +19,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include +#include #include #include @@ -32,6 +33,11 @@ namespace android { namespace renderengine { namespace skia { +static aidl::android::hardware::graphics::common::Dataspace toAidlDataspace( + ui::Dataspace dataspace) { + return static_cast(dataspace); +} + static void generateEOTF(ui::Dataspace dataspace, SkString& shader) { switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) { case HAL_DATASPACE_TRANSFER_ST2084: @@ -127,159 +133,13 @@ static void generateLuminanceScalesForOOTF(ui::Dataspace inputDataspace, SkStrin default: shader.append(R"( float3 ScaleLuminance(float3 xyz) { - return xyz * in_inputMaxLuminance; + return xyz * in_libtonemap_inputMaxLuminance; } )"); break; } } -static void generateToneMapInterpolation(ui::Dataspace inputDataspace, - ui::Dataspace outputDataspace, SkString& shader) { - switch (inputDataspace & HAL_DATASPACE_TRANSFER_MASK) { - case HAL_DATASPACE_TRANSFER_ST2084: - case HAL_DATASPACE_TRANSFER_HLG: - switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) { - case HAL_DATASPACE_TRANSFER_ST2084: - shader.append(R"( - float3 ToneMap(float3 xyz) { - return xyz; - } - )"); - break; - case HAL_DATASPACE_TRANSFER_HLG: - // PQ has a wider luminance range (10,000 nits vs. 1,000 nits) than HLG, so - // we'll clamp the luminance range in case we're mapping from PQ input to HLG - // output. - shader.append(R"( - float3 ToneMap(float3 xyz) { - return clamp(xyz, 0.0, 1000.0); - } - )"); - break; - default: - // Here we're mapping from HDR to SDR content, so interpolate using a Hermitian - // polynomial onto the smaller luminance range. - shader.append(R"( - float3 ToneMap(float3 xyz) { - float maxInLumi = in_inputMaxLuminance; - float maxOutLumi = in_displayMaxLuminance; - - float nits = xyz.y; - - // if the max input luminance is less than what we can output then - // no tone mapping is needed as all color values will be in range. - if (maxInLumi <= maxOutLumi) { - return xyz; - } else { - - // three control points - const float x0 = 10.0; - const float y0 = 17.0; - float x1 = maxOutLumi * 0.75; - float y1 = x1; - float x2 = x1 + (maxInLumi - x1) / 2.0; - float y2 = y1 + (maxOutLumi - y1) * 0.75; - - // horizontal distances between the last three control points - float h12 = x2 - x1; - float h23 = maxInLumi - x2; - // tangents at the last three control points - float m1 = (y2 - y1) / h12; - float m3 = (maxOutLumi - y2) / h23; - float m2 = (m1 + m3) / 2.0; - - if (nits < x0) { - // scale [0.0, x0] to [0.0, y0] linearly - float slope = y0 / x0; - return xyz * slope; - } else if (nits < x1) { - // scale [x0, x1] to [y0, y1] linearly - float slope = (y1 - y0) / (x1 - x0); - nits = y0 + (nits - x0) * slope; - } else if (nits < x2) { - // scale [x1, x2] to [y1, y2] using Hermite interp - float t = (nits - x1) / h12; - nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * (1.0 - t) + - (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t; - } else { - // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp - float t = (nits - x2) / h23; - nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * (1.0 - t) + - (maxOutLumi * (3.0 - 2.0 * t) + h23 * m3 * (t - 1.0)) * t * t; - } - } - - // color.y is greater than x0 and is thus non-zero - return xyz * (nits / xyz.y); - } - )"); - break; - } - break; - default: - switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) { - case HAL_DATASPACE_TRANSFER_ST2084: - case HAL_DATASPACE_TRANSFER_HLG: - // Map from SDR onto an HDR output buffer - // Here we use a polynomial curve to map from [0, displayMaxLuminance] onto - // [0, maxOutLumi] which is hard-coded to be 3000 nits. - shader.append(R"( - float3 ToneMap(float3 xyz) { - const float maxOutLumi = 3000.0; - - const float x0 = 5.0; - const float y0 = 2.5; - float x1 = in_displayMaxLuminance * 0.7; - float y1 = maxOutLumi * 0.15; - float x2 = in_displayMaxLuminance * 0.9; - float y2 = maxOutLumi * 0.45; - float x3 = in_displayMaxLuminance; - float y3 = maxOutLumi; - - float c1 = y1 / 3.0; - float c2 = y2 / 2.0; - float c3 = y3 / 1.5; - - float nits = xyz.y; - - if (nits <= x0) { - // scale [0.0, x0] to [0.0, y0] linearly - float slope = y0 / x0; - return xyz * slope; - } else if (nits <= x1) { - // scale [x0, x1] to [y0, y1] using a curve - float t = (nits - x0) / (x1 - x0); - nits = (1.0 - t) * (1.0 - t) * y0 + 2.0 * (1.0 - t) * t * c1 + t * t * y1; - } else if (nits <= x2) { - // scale [x1, x2] to [y1, y2] using a curve - float t = (nits - x1) / (x2 - x1); - nits = (1.0 - t) * (1.0 - t) * y1 + 2.0 * (1.0 - t) * t * c2 + t * t * y2; - } else { - // scale [x2, x3] to [y2, y3] using a curve - float t = (nits - x2) / (x3 - x2); - nits = (1.0 - t) * (1.0 - t) * y2 + 2.0 * (1.0 - t) * t * c3 + t * t * y3; - } - - // xyz.y is greater than x0 and is thus non-zero - return xyz * (nits / xyz.y); - } - )"); - break; - default: - // For completeness, this is tone-mapping from SDR to SDR, where this is just a - // no-op. - shader.append(R"( - float3 ToneMap(float3 xyz) { - return xyz; - } - )"); - break; - } - break; - } -} - // Normalizes from absolute light back to relative light (maps from [0, maxNits] back to [0, 1]) static void generateLuminanceNormalizationForOOTF(ui::Dataspace outputDataspace, SkString& shader) { switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) { @@ -300,7 +160,7 @@ static void generateLuminanceNormalizationForOOTF(ui::Dataspace outputDataspace, default: shader.append(R"( float3 NormalizeLuminance(float3 xyz) { - return xyz / in_displayMaxLuminance; + return xyz / in_libtonemap_displayMaxLuminance; } )"); break; @@ -309,19 +169,22 @@ static void generateLuminanceNormalizationForOOTF(ui::Dataspace outputDataspace, static void generateOOTF(ui::Dataspace inputDataspace, ui::Dataspace outputDataspace, SkString& shader) { - // Input uniforms - shader.append(R"( - uniform float in_displayMaxLuminance; - uniform float in_inputMaxLuminance; - )"); + shader.append(tonemap::getToneMapper() + ->generateTonemapGainShaderSkSL(toAidlDataspace(inputDataspace), + toAidlDataspace(outputDataspace)) + .c_str()); generateLuminanceScalesForOOTF(inputDataspace, shader); - generateToneMapInterpolation(inputDataspace, outputDataspace, shader); generateLuminanceNormalizationForOOTF(outputDataspace, shader); shader.append(R"( - float3 OOTF(float3 xyz) { - return NormalizeLuminance(ToneMap(ScaleLuminance(xyz))); + float3 OOTF(float3 linearRGB, float3 xyz) { + float3 scaledLinearRGB = ScaleLuminance(linearRGB); + float3 scaledXYZ = ScaleLuminance(xyz); + + float gain = libtonemap_LookupTonemapGain(scaledLinearRGB, scaledXYZ); + + return NormalizeLuminance(scaledXYZ * gain); } )"); } @@ -399,7 +262,9 @@ static void generateEffectiveOOTF(bool undoPremultipliedAlpha, SkString& shader) )"); } shader.append(R"( - c.rgb = OETF(ToRGB(OOTF(ToXYZ(EOTF(c.rgb))))); + float3 linearRGB = EOTF(c.rgb); + float3 xyz = ToXYZ(linearRGB); + c.rgb = OETF(ToRGB(OOTF(linearRGB, xyz))); )"); if (undoPremultipliedAlpha) { shader.append(R"( @@ -465,11 +330,20 @@ sk_sp createLinearEffectShader(sk_sp shader, const LinearEff colorTransform * mat4(outputColorSpace.getXYZtoRGB()); } - effectBuilder.uniform("in_displayMaxLuminance") = maxDisplayLuminance; - // If the input luminance is unknown, use display luminance (aka, no-op any luminance changes) - // This will be the case for eg screenshots in addition to uncalibrated displays - effectBuilder.uniform("in_inputMaxLuminance") = - maxLuminance > 0 ? maxLuminance : maxDisplayLuminance; + tonemap::Metadata metadata{.displayMaxLuminance = maxDisplayLuminance, + // If the input luminance is unknown, use display luminance (aka, + // no-op any luminance changes) + // This will be the case for eg screenshots in addition to + // uncalibrated displays + .contentMaxLuminance = + maxLuminance > 0 ? maxLuminance : maxDisplayLuminance}; + + const auto uniforms = tonemap::getToneMapper()->generateShaderSkSLUniforms(metadata); + + for (const auto& uniform : uniforms) { + effectBuilder.uniform(uniform.name.c_str()).set(uniform.value.data(), uniform.value.size()); + } + return effectBuilder.makeShader(nullptr, false); } diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp index d0e19dd4e2..52b6c8ff72 100644 --- a/libs/renderengine/tests/Android.bp +++ b/libs/renderengine/tests/Android.bp @@ -23,7 +23,10 @@ package { cc_test { name: "librenderengine_test", - defaults: ["skia_deps", "surfaceflinger_defaults"], + defaults: [ + "skia_deps", + "surfaceflinger_defaults", + ], test_suites: ["device-tests"], srcs: [ "RenderEngineTest.cpp", @@ -36,6 +39,7 @@ cc_test { "libgmock", "librenderengine", "librenderengine_mocks", + "libtonemap", ], shared_libs: [ diff --git a/libs/tonemap/Android.bp b/libs/tonemap/Android.bp new file mode 100644 index 0000000000..231a342852 --- /dev/null +++ b/libs/tonemap/Android.bp @@ -0,0 +1,37 @@ +// Copyright 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + +cc_library_static { + name: "libtonemap", + vendor_available: true, + + export_include_dirs: ["include"], + local_include_dirs: ["include"], + + shared_libs: [ + "android.hardware.graphics.common-V3-ndk", + ], + srcs: [ + "tonemap.cpp", + ], +} diff --git a/libs/tonemap/OWNERS b/libs/tonemap/OWNERS new file mode 100644 index 0000000000..6d91da3bd2 --- /dev/null +++ b/libs/tonemap/OWNERS @@ -0,0 +1,4 @@ +alecmouri@google.com +jreck@google.com +sallyqi@google.com +scroggo@google.com \ No newline at end of file diff --git a/libs/tonemap/TEST_MAPPING b/libs/tonemap/TEST_MAPPING new file mode 100644 index 0000000000..00f83baaa9 --- /dev/null +++ b/libs/tonemap/TEST_MAPPING @@ -0,0 +1,10 @@ +{ + "presubmit": [ + { + "name": "librenderengine_test" + }, + { + "name": "libtonemap_test" + } + ] +} diff --git a/libs/tonemap/include/tonemap/tonemap.h b/libs/tonemap/include/tonemap/tonemap.h new file mode 100644 index 0000000000..d350e160ca --- /dev/null +++ b/libs/tonemap/include/tonemap/tonemap.h @@ -0,0 +1,103 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include + +namespace android::tonemap { + +// Describes a shader uniform +// The shader uniform is intended to be passed into a SkRuntimeShaderBuilder, i.e.: +// +// SkRuntimeShaderBuilder builder; +// builder.uniform().set(.data(), .size()); +struct ShaderUniform { + // The name of the uniform, used for binding into a shader. + // The shader must contain a uniform whose name matches this. + std::string name; + + // The value for the uniform, which should be bound to the uniform identified by + std::vector value; +}; + +// Describes metadata which may be used for constructing the shader uniforms. +// This metadata should not be used for manipulating the source code of the shader program directly, +// as otherwise caching by other system of these shaders may break. +struct Metadata { + float displayMaxLuminance = 0.0; + float contentMaxLuminance = 0.0; +}; + +class ToneMapper { +public: + virtual ~ToneMapper() {} + // Constructs a tonemap shader whose shader language is SkSL + // + // The returned shader string *must* contain a function with the following signature: + // float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz); + // + // The arguments are: + // * linearRGB is the absolute nits of the RGB pixels in linear space + // * xyz is linearRGB converted into XYZ + // + // libtonemap_LookupTonemapGain() returns a float representing the amount by which to scale the + // absolute nits of the pixels. This function may be plugged into any existing SkSL shader, and + // is expected to look something like this: + // + // vec3 rgb = ...; + // // apply the EOTF based on the incoming dataspace to convert to linear nits. + // vec3 linearRGB = applyEOTF(rgb); + // // apply a RGB->XYZ matrix float3 + // vec3 xyz = toXYZ(linearRGB); + // // Scale the luminance based on the content standard + // vec3 absoluteRGB = ScaleLuminance(linearRGB); + // vec3 absoluteXYZ = ScaleLuminance(xyz); + // float gain = libtonemap_LookupTonemapGain(absoluteRGB, absoluteXYZ); + // // Normalize the luminance back down to a [0, 1] range + // xyz = NormalizeLuminance(absoluteXYZ * gain); + // // apply a XYZ->RGB matrix and apply the output OETf. + // vec3 finalColor = applyOETF(ToRGB(xyz)); + // ... + // + // Helper methods in this shader should be prefixed with "libtonemap_". Accordingly, libraries + // which consume this shader must *not* contain any methods prefixed with "libtonemap_" to + // guarantee that there are no conflicts in name resolution. + virtual std::string generateTonemapGainShaderSkSL( + aidl::android::hardware::graphics::common::Dataspace sourceDataspace, + aidl::android::hardware::graphics::common::Dataspace destinationDataspace) = 0; + + // Constructs uniform descriptions that correspond to those that are generated for the tonemap + // shader. Uniforms must be prefixed with "in_libtonemap_". Libraries which consume this shader + // must not bind any new uniforms that begin with this prefix. + // + // Downstream shaders may assume the existence of the uniform in_libtonemap_displayMaxLuminance + // and in_libtonemap_inputMaxLuminance, in order to assist with scaling and normalizing + // luminance as described in the documentation for generateTonemapGainShaderSkSL(). That is, + // shaders plugging in a tone-mapping shader returned by generateTonemapGainShaderSkSL() may + // assume that there are predefined floats in_libtonemap_displayMaxLuminance and + // in_libtonemap_inputMaxLuminance inside of the body of the tone-mapping shader. + virtual std::vector generateShaderSkSLUniforms(const Metadata& metadata) = 0; +}; + +// Retrieves a tonemapper instance. +// This instance is globally constructed. +ToneMapper* getToneMapper(); + +} // namespace android::tonemap \ No newline at end of file diff --git a/libs/tonemap/tests/Android.bp b/libs/tonemap/tests/Android.bp new file mode 100644 index 0000000000..e58d519224 --- /dev/null +++ b/libs/tonemap/tests/Android.bp @@ -0,0 +1,38 @@ +// Copyright 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + +cc_test { + name: "libtonemap_test", + test_suites: ["device-tests"], + srcs: [ + "tonemap_test.cpp", + ], + shared_libs: [ + "android.hardware.graphics.common-V3-ndk", + ], + static_libs: [ + "libgmock", + "libgtest", + "libtonemap", + ], +} diff --git a/libs/tonemap/tests/tonemap_test.cpp b/libs/tonemap/tests/tonemap_test.cpp new file mode 100644 index 0000000000..7a7958f58f --- /dev/null +++ b/libs/tonemap/tests/tonemap_test.cpp @@ -0,0 +1,76 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace android { + +using testing::HasSubstr; + +struct TonemapTest : public ::testing::Test {}; + +TEST_F(TonemapTest, generateShaderSkSLUniforms_containsDefaultUniforms) { + static const constexpr float kDisplayMaxLuminance = 1.f; + static const constexpr float kContentMaxLuminance = 2.f; + tonemap::Metadata metadata{.displayMaxLuminance = kDisplayMaxLuminance, + .contentMaxLuminance = kContentMaxLuminance}; + const auto uniforms = tonemap::getToneMapper()->generateShaderSkSLUniforms(metadata); + + ASSERT_EQ(1, std::count_if(uniforms.cbegin(), uniforms.cend(), [](const auto& data) { + return data.name == "in_libtonemap_displayMaxLuminance"; + })); + ASSERT_EQ(1, std::count_if(uniforms.cbegin(), uniforms.cend(), [](const auto& data) { + return data.name == "in_libtonemap_inputMaxLuminance"; + })); + + // Smoke check that metadata values are "real", specifically that they're non-zero and actually + // numbers. This is to help avoid shaders using these uniforms from dividing by zero or other + // catastrophic errors. + const auto& displayLum = std::find_if(uniforms.cbegin(), uniforms.cend(), [](const auto& data) { + return data.name == "in_libtonemap_displayMaxLuminance"; + })->value; + + float displayLumFloat = 0.f; + std::memcpy(&displayLumFloat, displayLum.data(), displayLum.size()); + EXPECT_FALSE(std::isnan(displayLumFloat)); + EXPECT_GT(displayLumFloat, 0); + + const auto& contentLum = std::find_if(uniforms.cbegin(), uniforms.cend(), [](const auto& data) { + return data.name == "in_libtonemap_inputMaxLuminance"; + })->value; + + float contentLumFloat = 0.f; + std::memcpy(&contentLumFloat, contentLum.data(), contentLum.size()); + EXPECT_FALSE(std::isnan(contentLumFloat)); + EXPECT_GT(contentLumFloat, 0); +} + +TEST_F(TonemapTest, generateTonemapGainShaderSkSL_containsEntryPoint) { + const auto shader = + tonemap::getToneMapper() + ->generateTonemapGainShaderSkSL(aidl::android::hardware::graphics::common:: + Dataspace::BT2020_ITU_PQ, + aidl::android::hardware::graphics::common:: + Dataspace::DISPLAY_P3); + + // Other tests such as librenderengine_test will plug in the shader to check compilation. + EXPECT_THAT(shader, HasSubstr("float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz)")); +} + +} // namespace android diff --git a/libs/tonemap/tonemap.cpp b/libs/tonemap/tonemap.cpp new file mode 100644 index 0000000000..350bca427c --- /dev/null +++ b/libs/tonemap/tonemap.cpp @@ -0,0 +1,256 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include + +namespace android::tonemap { + +namespace { + +// Flag containing the variant of tone map algorithm to use. +enum class ToneMapAlgorithm { + AndroidO, // Default algorithm in place since Android O, +}; + +static const constexpr auto kToneMapAlgorithm = ToneMapAlgorithm::AndroidO; + +static const constexpr auto kTransferMask = + static_cast(aidl::android::hardware::graphics::common::Dataspace::TRANSFER_MASK); +static const constexpr auto kTransferST2084 = + static_cast(aidl::android::hardware::graphics::common::Dataspace::TRANSFER_ST2084); +static const constexpr auto kTransferHLG = + static_cast(aidl::android::hardware::graphics::common::Dataspace::TRANSFER_HLG); + +template ::value, bool> = true> +std::vector buildUniformValue(T value) { + std::vector result; + result.resize(sizeof(value)); + std::memcpy(result.data(), &value, sizeof(value)); + return result; +} + +class ToneMapperO : public ToneMapper { +public: + std::string generateTonemapGainShaderSkSL( + aidl::android::hardware::graphics::common::Dataspace sourceDataspace, + aidl::android::hardware::graphics::common::Dataspace destinationDataspace) override { + const int32_t sourceDataspaceInt = static_cast(sourceDataspace); + const int32_t destinationDataspaceInt = static_cast(destinationDataspace); + + std::string program; + // Define required uniforms + program.append(R"( + uniform float in_libtonemap_displayMaxLuminance; + uniform float in_libtonemap_inputMaxLuminance; + )"); + switch (sourceDataspaceInt & kTransferMask) { + case kTransferST2084: + case kTransferHLG: + switch (destinationDataspaceInt & kTransferMask) { + case kTransferST2084: + program.append(R"( + float libtonemap_ToneMapTargetNits(vec3 xyz) { + return xyz.y; + } + )"); + break; + case kTransferHLG: + // PQ has a wider luminance range (10,000 nits vs. 1,000 nits) than HLG, so + // we'll clamp the luminance range in case we're mapping from PQ input to + // HLG output. + program.append(R"( + float libtonemap_ToneMapTargetNits(vec3 xyz) { + return clamp(xyz.y, 0.0, 1000.0); + } + )"); + break; + default: + // Here we're mapping from HDR to SDR content, so interpolate using a + // Hermitian polynomial onto the smaller luminance range. + program.append(R"( + float libtonemap_ToneMapTargetNits(vec3 xyz) { + float maxInLumi = in_libtonemap_inputMaxLuminance; + float maxOutLumi = in_libtonemap_displayMaxLuminance; + + float nits = xyz.y; + + // if the max input luminance is less than what we can + // output then no tone mapping is needed as all color + // values will be in range. + if (maxInLumi <= maxOutLumi) { + return xyz.y; + } else { + + // three control points + const float x0 = 10.0; + const float y0 = 17.0; + float x1 = maxOutLumi * 0.75; + float y1 = x1; + float x2 = x1 + (maxInLumi - x1) / 2.0; + float y2 = y1 + (maxOutLumi - y1) * 0.75; + + // horizontal distances between the last three + // control points + float h12 = x2 - x1; + float h23 = maxInLumi - x2; + // tangents at the last three control points + float m1 = (y2 - y1) / h12; + float m3 = (maxOutLumi - y2) / h23; + float m2 = (m1 + m3) / 2.0; + + if (nits < x0) { + // scale [0.0, x0] to [0.0, y0] linearly + float slope = y0 / x0; + return nits * slope; + } else if (nits < x1) { + // scale [x0, x1] to [y0, y1] linearly + float slope = (y1 - y0) / (x1 - x0); + nits = y0 + (nits - x0) * slope; + } else if (nits < x2) { + // scale [x1, x2] to [y1, y2] using Hermite interp + float t = (nits - x1) / h12; + nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * + (1.0 - t) * (1.0 - t) + + (y2 * (3.0 - 2.0 * t) + + h12 * m2 * (t - 1.0)) * t * t; + } else { + // scale [x2, maxInLumi] to [y2, maxOutLumi] using + // Hermite interp + float t = (nits - x2) / h23; + nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * + (1.0 - t) * (1.0 - t) + (maxOutLumi * + (3.0 - 2.0 * t) + h23 * m3 * + (t - 1.0)) * t * t; + } + } + + return nits; + } + )"); + break; + } + break; + default: + switch (destinationDataspaceInt & kTransferMask) { + case kTransferST2084: + case kTransferHLG: + // Map from SDR onto an HDR output buffer + // Here we use a polynomial curve to map from [0, displayMaxLuminance] onto + // [0, maxOutLumi] which is hard-coded to be 3000 nits. + program.append(R"( + float libtonemap_ToneMapTargetNits(vec3 xyz) { + const float maxOutLumi = 3000.0; + + const float x0 = 5.0; + const float y0 = 2.5; + float x1 = in_libtonemap_displayMaxLuminance * 0.7; + float y1 = maxOutLumi * 0.15; + float x2 = in_libtonemap_displayMaxLuminance * 0.9; + float y2 = maxOutLumi * 0.45; + float x3 = in_libtonemap_displayMaxLuminance; + float y3 = maxOutLumi; + + float c1 = y1 / 3.0; + float c2 = y2 / 2.0; + float c3 = y3 / 1.5; + + float nits = xyz.y; + + if (nits <= x0) { + // scale [0.0, x0] to [0.0, y0] linearly + float slope = y0 / x0; + return nits * slope; + } else if (nits <= x1) { + // scale [x0, x1] to [y0, y1] using a curve + float t = (nits - x0) / (x1 - x0); + nits = (1.0 - t) * (1.0 - t) * y0 + + 2.0 * (1.0 - t) * t * c1 + t * t * y1; + } else if (nits <= x2) { + // scale [x1, x2] to [y1, y2] using a curve + float t = (nits - x1) / (x2 - x1); + nits = (1.0 - t) * (1.0 - t) * y1 + + 2.0 * (1.0 - t) * t * c2 + t * t * y2; + } else { + // scale [x2, x3] to [y2, y3] using a curve + float t = (nits - x2) / (x3 - x2); + nits = (1.0 - t) * (1.0 - t) * y2 + + 2.0 * (1.0 - t) * t * c3 + t * t * y3; + } + + return nits; + } + )"); + break; + default: + // For completeness, this is tone-mapping from SDR to SDR, where this is + // just a no-op. + program.append(R"( + float libtonemap_ToneMapTargetNits(vec3 xyz) { + return xyz.y; + } + )"); + break; + } + break; + } + + program.append(R"( + float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz) { + if (xyz.y <= 0.0) { + return 1.0; + } + return libtonemap_ToneMapTargetNits(xyz) / xyz.y; + } + )"); + return program; + } + + std::vector generateShaderSkSLUniforms(const Metadata& metadata) override { + std::vector uniforms; + + uniforms.reserve(2); + + uniforms.push_back({.name = "in_libtonemap_displayMaxLuminance", + .value = buildUniformValue(metadata.displayMaxLuminance)}); + uniforms.push_back({.name = "in_libtonemap_inputMaxLuminance", + .value = buildUniformValue(metadata.contentMaxLuminance)}); + + return uniforms; + } +}; + +} // namespace + +ToneMapper* getToneMapper() { + static std::once_flag sOnce; + static std::unique_ptr sToneMapper; + + std::call_once(sOnce, [&] { + switch (kToneMapAlgorithm) { + case ToneMapAlgorithm::AndroidO: + sToneMapper = std::unique_ptr(new ToneMapperO()); + break; + } + }); + + return sToneMapper.get(); +} + +} // namespace android::tonemap \ No newline at end of file diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 56b8374eb0..6691575d32 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -79,6 +79,7 @@ cc_defaults { "libperfetto_client_experimental", "librenderengine", "libserviceutils", + "libtonemap", "libtrace_proto", "libaidlcommonsupport", ], diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 83b4a2552b..aefc014062 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -38,6 +38,7 @@ cc_defaults { static_libs: [ "libmath", "librenderengine", + "libtonemap", "libtrace_proto", "libaidlcommonsupport", ], diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index f152cedf46..1ac568066e 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -142,6 +142,7 @@ cc_test { "libtimestats", "libtimestats_atoms_proto", "libtimestats_proto", + "libtonemap", "libtrace_proto", "perfetto_trace_protos", ], -- cgit v1.2.3-59-g8ed1b From c33c63aba9b234eff8a3487c14946bf5bbea3bb5 Mon Sep 17 00:00:00 2001 From: Jiakai Zhang Date: Tue, 9 Nov 2021 11:24:04 +0000 Subject: Revert "BBQ: Clean up acquire states on BQ disconnect" This reverts commit 9051fb1885df913eecfa9072155797bdaf05d278. Reason for revert: Potential culprit CL for broken test b/205665388 Change-Id: Iba58d8de19851beedf46511fbefa837e3f3f7ad2 --- libs/gui/BLASTBufferQueue.cpp | 73 +++------------------------- libs/gui/include/gui/BLASTBufferQueue.h | 12 ----- services/surfaceflinger/BufferStateLayer.cpp | 2 +- services/surfaceflinger/BufferStateLayer.h | 1 - 4 files changed, 8 insertions(+), 80 deletions(-) diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 9cb7c88956..9080822f92 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -58,22 +58,13 @@ namespace android { ALOGE("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__) void BLASTBufferItemConsumer::onDisconnect() { - { - Mutex::Autolock lock(mMutex); - mPreviouslyConnected = mCurrentlyConnected; - mCurrentlyConnected = false; - if (mPreviouslyConnected) { - mDisconnectEvents.push(mCurrentFrameNumber); - } - mFrameEventHistory.onDisconnect(); - } - - { - std::scoped_lock lock(mBufferQueueMutex); - if (mBLASTBufferQueue != nullptr) { - mBLASTBufferQueue->onProducerDisconnect(); - } + Mutex::Autolock lock(mMutex); + mPreviouslyConnected = mCurrentlyConnected; + mCurrentlyConnected = false; + if (mPreviouslyConnected) { + mDisconnectEvents.push(mCurrentFrameNumber); } + mFrameEventHistory.onDisconnect(); } void BLASTBufferItemConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, @@ -211,11 +202,7 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, } SurfaceComposerClient::Transaction t; - bool setBackpressureFlag = false; - if (!SurfaceControl::isSameSurface(mSurfaceControl, surface)) { - mSurfaceControlSwapCount++; - setBackpressureFlag = true; - } + const bool setBackpressureFlag = !SurfaceControl::isSameSurface(mSurfaceControl, surface); bool applyTransaction = false; // Always update the native object even though they might have the same layer handle, so we can @@ -401,19 +388,6 @@ void BLASTBufferQueue::releaseBufferCallback( std::unique_lock _lock{mMutex}; BQA_LOGV("releaseBufferCallback %s", id.to_string().c_str()); - const auto it = mFreedBuffers.find(id); - if (it != mFreedBuffers.end()) { - mFreedBuffers.erase(it); - BQA_LOGV("releaseBufferCallback ignoring freed buffer %s", id.to_string().c_str()); - return; - } - - if (mFreedBuffers.size() != 0 && mLogMissingReleaseCallback) { - BQA_LOGD("Unexpected out of order buffer release. mFreedBuffer count=%d", - static_cast(mFreedBuffers.size())); - mLogMissingReleaseCallback = false; - } - // Calculate how many buffers we need to hold before we release them back // to the buffer queue. This will prevent higher latency when we are running // on a lower refresh rate than the max supported. We only do that for EGL @@ -619,12 +593,6 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { ATRACE_CALL(); std::unique_lock _lock{mMutex}; - if ((mSurfaceControlSwapCount > mProducerDisconnectCount) && mLogScSwap) { - BQA_LOGD("Expected producer disconnect sc swap count=%d bq disconnect count=%d", - mSurfaceControlSwapCount, mProducerDisconnectCount); - mLogScSwap = false; - } - const bool nextTransactionSet = mNextTransaction != nullptr; BQA_LOGV("onFrameAvailable-start nextTransactionSet=%s", boolToString(nextTransactionSet)); if (nextTransactionSet) { @@ -991,31 +959,4 @@ uint64_t BLASTBufferQueue::getLastAcquiredFrameNum() { return mLastAcquiredFrameNumber; } -// When the producer disconnects, all buffers in the queue will be freed. So clean up the bbq -// acquire state and handle any pending release callbacks. If we do get a release callback for a -// pending buffer for a disconnected queue, we cannot release the buffer back to the queue. So track -// these separately and drop the release callbacks as they come. - -// Transaction callbacks are still expected to come in the order they were submitted regardless of -// buffer queue state. So we can continue to handles the pending transactions and transaction -// complete callbacks. When the queue is reconnected, the queue will increment the framenumbers -// starting from the last queued framenumber. -void BLASTBufferQueue::onProducerDisconnect() { - BQA_LOGV("onProducerDisconnect"); - std::scoped_lock _lock{mMutex}; - // reset counts since the queue has been disconnected and all buffers have been freed. - mNumFrameAvailable = 0; - mNumAcquired = 0; - - // Track submitted buffers in a different container so we can handle any pending release buffer - // callbacks without affecting the BBQ acquire state. - mFreedBuffers.insert(mSubmitted.begin(), mSubmitted.end()); - mSubmitted.clear(); - mPendingRelease.clear(); - mProducerDisconnectCount++; - mCallbackCV.notify_all(); - mLogMissingReleaseCallback = true; - mLogScSwap = true; -} - } // namespace android diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 72567e3f93..3881620f3d 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -109,8 +109,6 @@ public: uint32_t getLastTransformHint() const; uint64_t getLastAcquiredFrameNum(); - void onProducerDisconnect(); - virtual ~BLASTBufferQueue(); private: @@ -158,12 +156,6 @@ private: std::unordered_map mSubmitted GUARDED_BY(mMutex); - // Keep a reference to the submitted buffers that were freed so we can drop the buffer quietly - // when we get the release callback from flinger. This can happen if the client had disconnected - // from the queue. - std::unordered_map mFreedBuffers - GUARDED_BY(mMutex); - // Keep a queue of the released buffers instead of immediately releasing // the buffers back to the buffer queue. This would be controlled by SF // setting the max acquired buffer count. @@ -248,10 +240,6 @@ private: uint32_t mCurrentMaxAcquiredBufferCount; bool mWaitForTransactionCallback = false; - bool mLogScSwap = true; - bool mLogMissingReleaseCallback = true; - uint32_t mSurfaceControlSwapCount = 0; - uint32_t mProducerDisconnectCount = 0; }; } // namespace android diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 25fb6ce2ae..c0753f9d47 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -404,7 +404,7 @@ bool BufferStateLayer::setBuffer(const BufferData& bufferData, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, std::optional dequeueTime, const FrameTimelineInfo& info) { - ATRACE_NAME(mSetBufferTraceTag.c_str()); + ATRACE_CALL(); const std::shared_ptr& buffer = getBufferFromBufferData(bufferData); diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 3aa60826d0..eea700cf7b 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -153,7 +153,6 @@ private: static constexpr int kPendingClassificationMaxSurfaceFrames = 25; const std::string mBlastTransactionName{"BufferTX - " + mName}; - const std::string mSetBufferTraceTag{"setBuffer - " + mName}; // This integer is incremented everytime a buffer arrives at the server for this layer, // and decremented when a buffer is dropped or latched. When changed the integer is exported // to systrace with ATRACE_INT and mBlastTransactionName. This way when debugging perf it is -- cgit v1.2.3-59-g8ed1b From a5505cb8fa988023685e8d67fcc8117ee7c63b1e Mon Sep 17 00:00:00 2001 From: Jiakai Zhang Date: Tue, 9 Nov 2021 11:46:30 +0000 Subject: Revert "SurfaceFlinger: Emit callbacks for non-buffer layer transactions" This reverts commit da1fd1508c914c7f0849e4e00a5fae5412433337. Reason for revert: Potential culprit CL for broken test b/205501709 Change-Id: Iece745e0690f4d31b93918697b306ded3abfd0d0 --- services/surfaceflinger/BufferStateLayer.cpp | 15 ++------ services/surfaceflinger/BufferStateLayer.h | 3 +- services/surfaceflinger/Layer.cpp | 11 ------ services/surfaceflinger/Layer.h | 6 ++- services/surfaceflinger/SurfaceFlinger.cpp | 21 +++++----- .../surfaceflinger/TransactionCallbackInvoker.cpp | 8 ++-- .../surfaceflinger/TransactionCallbackInvoker.h | 12 +++--- .../surfaceflinger/tests/LayerCallback_test.cpp | 45 +--------------------- 8 files changed, 32 insertions(+), 89 deletions(-) diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 3e09a40eba..c213570c7f 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -549,19 +549,13 @@ bool BufferStateLayer::setSidebandStream(const sp& sidebandStream) } bool BufferStateLayer::setTransactionCompletedListeners( - const std::vector& listenerCallbacks, const sp& layerHandle) { + const std::vector>& handles) { // If there is no handle, we will not send a callback so reset mReleasePreviousBuffer and return - if (listenerCallbacks.empty()) { + if (handles.empty()) { mReleasePreviousBuffer = false; return false; } - std::vector> handles; - handles.reserve(listenerCallbacks.size()); - for (auto& [listener, callbackIds] : listenerCallbacks) { - handles.emplace_back(new CallbackHandle(listener, callbackIds, layerHandle)); - } - const bool willPresent = willPresentCurrentTransaction(); for (const auto& handle : handles) { @@ -577,10 +571,9 @@ bool BufferStateLayer::setTransactionCompletedListeners( // Store so latched time and release fence can be set mDrawingState.callbackHandles.push_back(handle); - } else { - // If this layer will NOT need to be relatched and presented this frame + } else { // If this layer will NOT need to be relatched and presented this frame // Notify the transaction completed thread this handle is done - mFlinger->getTransactionCallbackInvoker().addUnpresentedCallbackHandle(handle); + mFlinger->getTransactionCallbackInvoker().registerUnpresentedCallbackHandle(handle); } } diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index ceed188f0e..eea700cf7b 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -65,8 +65,7 @@ public: bool setSurfaceDamageRegion(const Region& surfaceDamage) override; bool setApi(int32_t api) override; bool setSidebandStream(const sp& sidebandStream) override; - bool setTransactionCompletedListeners(const std::vector& handles, - const sp& layerHandle) override; + bool setTransactionCompletedListeners(const std::vector>& handles) override; bool addFrameEvent(const sp& acquireFence, nsecs_t postedTime, nsecs_t requestedPresentTime) override; bool setPosition(float /*x*/, float /*y*/) override; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d8854d3033..d68cf9720f 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2645,17 +2645,6 @@ bool Layer::setDropInputMode(gui::DropInputMode mode) { return true; } -bool Layer::setTransactionCompletedListeners( - const std::vector& listenerCallbacks, const sp&) { - if (listenerCallbacks.empty()) { - return false; - } - for (auto& listener : listenerCallbacks) { - mFlinger->getTransactionCallbackInvoker().addEmptyCallback(listener); - } - return false; -} - // --------------------------------------------------------------------------- std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index f6f162128f..4569f9af23 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -426,8 +426,10 @@ public: virtual bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/) { return false; }; virtual bool setApi(int32_t /*api*/) { return false; }; virtual bool setSidebandStream(const sp& /*sidebandStream*/) { return false; }; - virtual bool setTransactionCompletedListeners(const std::vector& /*handles*/, - const sp& /* layerHandle */); + virtual bool setTransactionCompletedListeners( + const std::vector>& /*handles*/) { + return false; + }; virtual bool addFrameEvent(const sp& /*acquireFence*/, nsecs_t /*postedTime*/, nsecs_t /*requestedPresentTime*/) { return false; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index af6d00041e..53a4ae02eb 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3727,10 +3727,11 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin transactionFlags |= setDisplayStateLocked(display); } - // Add listeners w/ surfaces so they can get their callback. Note that listeners with - // SurfaceControls will start registration during setClientStateLocked below. + // start and end registration for listeners w/ no surface so they can get their callback. Note + // that listeners with SurfaceControls will start registration during setClientStateLocked + // below. for (const auto& listener : listenerCallbacks) { - mTransactionCallbackInvoker.addEmptyCallback(listener); + mTransactionCallbackInvoker.addEmptyTransaction(listener); } uint32_t clientStateFlags = 0; @@ -3902,7 +3903,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime } if (layer == nullptr) { for (auto& [listener, callbackIds] : s.listeners) { - mTransactionCallbackInvoker.addUnpresentedCallbackHandle( + mTransactionCallbackInvoker.registerUnpresentedCallbackHandle( new CallbackHandle(listener, callbackIds, s.surface)); } return 0; @@ -4172,6 +4173,12 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime flags |= eTransactionNeeded | eTraversalNeeded; } } + std::vector> callbackHandles; + if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!filteredListeners.empty())) { + for (auto& [listener, callbackIds] : filteredListeners) { + callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface)); + } + } if (what & layer_state_t::eBufferChanged && layer->setBuffer(s.bufferData, postTime, desiredPresentTime, isAutoTimestamp, @@ -4181,11 +4188,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime layer->setFrameTimelineVsyncForBufferlessTransaction(frameTimelineInfo, postTime); } - if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!filteredListeners.empty())) { - if (layer->setTransactionCompletedListeners(filteredListeners, s.surface)) { - flags |= eTraversalNeeded; - } - } + if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded; // Do not put anything that updates layer state or modifies flags after // setTransactionCompletedListener return flags; diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index 418fbc5c44..f3d46ea061 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -74,10 +74,10 @@ TransactionCallbackInvoker::~TransactionCallbackInvoker() { } } -void TransactionCallbackInvoker::addEmptyCallback(const ListenerCallbacks& listenerCallbacks) { +void TransactionCallbackInvoker::addEmptyTransaction(const ListenerCallbacks& listenerCallbacks) { auto& [listener, callbackIds] = listenerCallbacks; - TransactionStats* transactionStats; - findOrCreateTransactionStats(listener, callbackIds, &transactionStats); + auto& transactionStatsDeque = mCompletedTransactions[listener]; + transactionStatsDeque.emplace_back(callbackIds); } status_t TransactionCallbackInvoker::addOnCommitCallbackHandles( @@ -116,7 +116,7 @@ status_t TransactionCallbackInvoker::addCallbackHandles( return NO_ERROR; } -status_t TransactionCallbackInvoker::addUnpresentedCallbackHandle( +status_t TransactionCallbackInvoker::registerUnpresentedCallbackHandle( const sp& handle) { return addCallbackHandle(handle, std::vector()); } diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index 6f67947081..e203d41bd9 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -71,10 +71,8 @@ public: // Adds the Transaction CallbackHandle from a layer that does not need to be relatched and // presented this frame. - status_t addUnpresentedCallbackHandle(const sp& handle); - // Adds the callback handles for empty transactions or for non-buffer layer updates which do not - // include layer stats. - void addEmptyCallback(const ListenerCallbacks& listenerCallbacks); + status_t registerUnpresentedCallbackHandle(const sp& handle); + void addEmptyTransaction(const ListenerCallbacks& listenerCallbacks); void addPresentFence(const sp& presentFence); @@ -83,12 +81,14 @@ public: mCompletedTransactions.clear(); } + status_t addCallbackHandle(const sp& handle, + const std::vector& jankData); + + private: status_t findOrCreateTransactionStats(const sp& listener, const std::vector& callbackIds, TransactionStats** outTransactionStats); - status_t addCallbackHandle(const sp& handle, - const std::vector& jankData); std::unordered_map, std::deque, IListenerHash> mCompletedTransactions; diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp index 7beba15062..91a5b528f8 100644 --- a/services/surfaceflinger/tests/LayerCallback_test.cpp +++ b/services/surfaceflinger/tests/LayerCallback_test.cpp @@ -1067,7 +1067,7 @@ TEST_F(LayerCallbackTest, EmptyBufferStateChanges) { } // b202394221 -TEST_F(LayerCallbackTest, NonBufferLayerStateChanges) { +TEST_F(LayerCallbackTest, DISABLED_NonBufferLayerStateChanges) { sp layer; ASSERT_NO_FATAL_FAILURE(layer = createColorLayer("ColorLayer", Color::RED)); @@ -1085,47 +1085,4 @@ TEST_F(LayerCallbackTest, NonBufferLayerStateChanges) { EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true)); } -class TimedCallbackHelper { -public: - static void function(void* callbackContext, nsecs_t, const sp&, - const std::vector&) { - if (!callbackContext) { - ALOGE("failed to get callback context"); - } - TimedCallbackHelper* helper = static_cast(callbackContext); - std::lock_guard lock(helper->mMutex); - helper->mInvokedTime = systemTime(); - helper->mCv.notify_all(); - } - - void waitForCallback() { - std::unique_lock lock(mMutex); - ASSERT_TRUE(mCv.wait_for(lock, std::chrono::seconds(3), [&] { return mInvokedTime != -1; })) - << "did not receive callback"; - } - void* getContext() { return static_cast(this); } - - std::mutex mMutex; - std::condition_variable mCv; - nsecs_t mInvokedTime = -1; -}; - -TEST_F(LayerCallbackTest, EmptyTransactionCallbackOrder) { - TimedCallbackHelper onCommitCallback; - TimedCallbackHelper onCompleteCallback; - - // Add transaction callback before on commit callback - Transaction() - .addTransactionCompletedCallback(onCompleteCallback.function, - onCompleteCallback.getContext()) - .addTransactionCommittedCallback(onCommitCallback.function, - onCommitCallback.getContext()) - .apply(); - - EXPECT_NO_FATAL_FAILURE(onCompleteCallback.waitForCallback()); - EXPECT_NO_FATAL_FAILURE(onCommitCallback.waitForCallback()); - // verify we get the oncomplete at the same time or after the oncommit callback. - EXPECT_GE(onCompleteCallback.mInvokedTime, onCommitCallback.mInvokedTime); -} - } // namespace android -- cgit v1.2.3-59-g8ed1b From 6b9ffea5e6bdc56c2a54bb6a1c8b18ee86ce8d48 Mon Sep 17 00:00:00 2001 From: chaviw Date: Mon, 8 Nov 2021 09:25:48 -0600 Subject: Invoke commit callback after latch buffers If commit callback is invoked before the buffers can be latched, they won't be included in the commit callback and would only be invoked in the complete callback. This defeats the purpose of the commit callback as an early indicator that the buffer has been committed. Move the commit callback invocation so it's after latchBuffers This also fixes a bug where offscreen layers could be latched in flushAndCommitTransactions, so only offscreen layers would get the commit callback. This would cause issues if the offscreen layer transaction was merged with a layer that was on screen, preventing the on screen layer from getting a commit callback. Test: LayerCallbackTest#CommitCallbackOffscreenLayer Test: BLASTBufferQueueTest Test: BLASTBufferQueueTransformTest Test: BLASTFrameEventHistoryTest Fixes: 205563588 Change-Id: I5692211dd7717258829be8eb8a68b2dcb4a5498d --- libs/gui/include/gui/BLASTBufferQueue.h | 8 ++-- libs/gui/tests/BLASTBufferQueue_test.cpp | 19 ++++---- services/surfaceflinger/SurfaceFlinger.cpp | 55 ++++++++++------------ services/surfaceflinger/SurfaceFlinger.h | 3 -- .../surfaceflinger/tests/LayerCallback_test.cpp | 44 +++++++++++++++++ 5 files changed, 83 insertions(+), 46 deletions(-) diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 3881620f3d..4a63544464 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -88,10 +88,10 @@ public: void onFrameDequeued(const uint64_t) override; void onFrameCancelled(const uint64_t) override; - virtual void transactionCommittedCallback(nsecs_t latchTime, const sp& presentFence, - const std::vector& stats); - void transactionCallback(nsecs_t latchTime, const sp& presentFence, - const std::vector& stats); + void transactionCommittedCallback(nsecs_t latchTime, const sp& presentFence, + const std::vector& stats); + virtual void transactionCallback(nsecs_t latchTime, const sp& presentFence, + const std::vector& stats); void releaseBufferCallback(const ReleaseCallbackId& id, const sp& releaseFence, std::optional currentMaxAcquiredBufferCount); void setNextTransaction(SurfaceComposerClient::Transaction *t); diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index b2d50482a5..8607e1d83c 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -72,31 +72,30 @@ public: int height, int32_t format) : BLASTBufferQueue(name, surface, width, height, format) {} - void transactionCommittedCallback(nsecs_t latchTime, const sp& presentFence, - const std::vector& stats) override { - BLASTBufferQueue::transactionCommittedCallback(latchTime, presentFence, stats); - + void transactionCallback(nsecs_t latchTime, const sp& presentFence, + const std::vector& stats) override { + BLASTBufferQueue::transactionCallback(latchTime, presentFence, stats); uint64_t frameNumber = stats[0].frameEventStats.frameNumber; { std::unique_lock lock{frameNumberMutex}; - mLastTransactionCommittedFrameNumber = frameNumber; - mCommittedCV.notify_all(); + mLastTransactionFrameNumber = frameNumber; + mWaitForCallbackCV.notify_all(); } } void waitForCallback(int64_t frameNumber) { std::unique_lock lock{frameNumberMutex}; // Wait until all but one of the submitted buffers have been released. - while (mLastTransactionCommittedFrameNumber < frameNumber) { - mCommittedCV.wait(lock); + while (mLastTransactionFrameNumber < frameNumber) { + mWaitForCallbackCV.wait(lock); } } private: std::mutex frameNumberMutex; - std::condition_variable mCommittedCV; - int64_t mLastTransactionCommittedFrameNumber = -1; + std::condition_variable mWaitForCallbackCV; + int64_t mLastTransactionFrameNumber = -1; }; class BLASTBufferQueueHelper { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d0f2174ad6..98f2107633 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1971,9 +1971,34 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected mFrameTimeline->setSfWakeUp(vsyncId, frameTime, Fps::fromPeriodNsecs(stats.vsyncPeriod)); - mustComposite |= flushAndCommitTransactions(); + bool needsTraversal = false; + if (clearTransactionFlags(eTransactionFlushNeeded)) { + needsTraversal = flushTransactionQueues(); + } + + const bool shouldCommit = + (getTransactionFlags() & ~eTransactionFlushNeeded) || needsTraversal; + if (shouldCommit) { + commitTransactions(); + } + + if (transactionFlushNeeded()) { + setTransactionFlags(eTransactionFlushNeeded); + } + + mustComposite |= shouldCommit; mustComposite |= latchBuffers(); + // This has to be called after latchBuffers because we want to include the layers that have + // been latched in the commit callback + if (!needsTraversal) { + // Invoke empty transaction callbacks early. + mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */); + } else { + // Invoke OnCommit callbacks. + mTransactionCallbackInvoker.sendCallbacks(true /* onCommitOnly */); + } + updateLayerGeometry(); if (tracePreComposition) { @@ -2000,34 +2025,6 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER); } -bool SurfaceFlinger::flushAndCommitTransactions() { - ATRACE_CALL(); - - bool needsTraversal = false; - if (clearTransactionFlags(eTransactionFlushNeeded)) { - needsTraversal = flushTransactionQueues(); - } - - const bool shouldCommit = (getTransactionFlags() & ~eTransactionFlushNeeded) || needsTraversal; - if (shouldCommit) { - commitTransactions(); - } - - if (!needsTraversal) { - // Invoke empty transaction callbacks early. - mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */); - } else { - // Invoke OnCommit callbacks. - mTransactionCallbackInvoker.sendCallbacks(true /* onCommitOnly */); - } - - if (transactionFlushNeeded()) { - setTransactionFlags(eTransactionFlushNeeded); - } - - return shouldCommit; -} - void SurfaceFlinger::composite(nsecs_t frameTime) { ATRACE_CALL(); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index bf628dc309..5c85382dfd 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -684,9 +684,6 @@ private: const std::optional& policy, bool overridePolicy) EXCLUDES(mStateLock); - // Returns whether transactions were committed. - bool flushAndCommitTransactions() EXCLUDES(mStateLock); - void commitTransactions() EXCLUDES(mStateLock); void commitTransactionsLocked(uint32_t transactionFlags) REQUIRES(mStateLock); void doCommitTransactions() REQUIRES(mStateLock); diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp index 91a5b528f8..5c16feeda8 100644 --- a/services/surfaceflinger/tests/LayerCallback_test.cpp +++ b/services/surfaceflinger/tests/LayerCallback_test.cpp @@ -26,6 +26,7 @@ using namespace std::chrono_literals; namespace android { using android::hardware::graphics::common::V1_1::BufferUsage; +using SCHash = SurfaceComposerClient::SCHash; ::testing::Environment* const binderEnv = ::testing::AddGlobalTestEnvironment(new BinderEnvironment()); @@ -102,6 +103,24 @@ public: } } + static void waitForCommitCallback( + CallbackHelper& helper, + const std::unordered_set, SCHash>& committedSc) { + CallbackData callbackData; + ASSERT_NO_FATAL_FAILURE(helper.getCallbackData(&callbackData)); + + const auto& surfaceControlStats = callbackData.surfaceControlStats; + + ASSERT_EQ(surfaceControlStats.size(), committedSc.size()) << "wrong number of surfaces"; + + for (const auto& stats : surfaceControlStats) { + ASSERT_NE(stats.surfaceControl, nullptr) << "returned null surface control"; + + const auto& expectedSc = committedSc.find(stats.surfaceControl); + ASSERT_NE(expectedSc, committedSc.end()) << "unexpected surface control"; + } + } + DisplayEventReceiver mDisplayEventReceiver; int mEpollFd; @@ -1085,4 +1104,29 @@ TEST_F(LayerCallbackTest, DISABLED_NonBufferLayerStateChanges) { EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true)); } +TEST_F(LayerCallbackTest, CommitCallbackOffscreenLayer) { + sp layer; + ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + sp offscreenLayer = + createSurface(mClient, "Offscreen Layer", 0, 0, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState, layer.get()); + + Transaction transaction; + CallbackHelper callback; + int err = fillTransaction(transaction, &callback, layer, true); + err |= fillTransaction(transaction, &callback, offscreenLayer, true); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + + transaction.reparent(offscreenLayer, nullptr) + .addTransactionCommittedCallback(callback.function, callback.getContext()); + transaction.apply(); + + std::unordered_set, SCHash> committedSc; + committedSc.insert(layer); + committedSc.insert(offscreenLayer); + EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc)); +} } // namespace android -- cgit v1.2.3-59-g8ed1b From 9c93d60fb7257a1b79180d8d38664df45cc1e2c2 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Thu, 7 Oct 2021 19:38:26 -0700 Subject: SF: Split Scheduler initialization Create VsyncSchedule and timers after Scheduler construction, which will happen on boot rather than initial hotplug in the future. Remove Scheduler from SF factory. Bug: 185535769 Test: Boot Change-Id: I1096987f468a43fa4b6ae39709b44425d026248c --- services/surfaceflinger/Scheduler/Scheduler.cpp | 56 +++++++--------------- services/surfaceflinger/Scheduler/Scheduler.h | 29 +++++------ services/surfaceflinger/SurfaceFlinger.cpp | 15 +++++- .../SurfaceFlingerDefaultFactory.cpp | 6 --- .../surfaceflinger/SurfaceFlingerDefaultFactory.h | 2 - services/surfaceflinger/SurfaceFlingerFactory.h | 2 - .../tests/unittests/CompositionTest.cpp | 7 +-- .../tests/unittests/LayerHistoryTest.cpp | 6 +-- .../tests/unittests/SchedulerTest.cpp | 20 +++----- .../tests/unittests/SetFrameRateTest.cpp | 24 ++++------ .../tests/unittests/TestableScheduler.h | 28 ++++------- .../tests/unittests/TestableSurfaceFlinger.h | 5 -- 12 files changed, 71 insertions(+), 129 deletions(-) diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index eeea25df7d..f201996394 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -117,16 +117,10 @@ private: } }; -Scheduler::Scheduler(const std::shared_ptr& configs, - ISchedulerCallback& callback) - : Scheduler(configs, callback, - {.useContentDetection = sysprop::use_content_detection_for_refresh_rate(false)}) { -} +Scheduler::Scheduler(ISchedulerCallback& callback, Options options) + : mOptions(options), mSchedulerCallback(callback) {} -Scheduler::Scheduler(const std::shared_ptr& configs, - ISchedulerCallback& callback, Options options) - : Scheduler(createVsyncSchedule(configs->supportsKernelIdleTimer()), configs, callback, - createLayerHistory(), options) { +void Scheduler::startTimers() { using namespace sysprop; if (const int64_t millis = set_touch_timer_ms(0); millis > 0) { @@ -147,22 +141,6 @@ Scheduler::Scheduler(const std::shared_ptr& confi } } -Scheduler::Scheduler(VsyncSchedule schedule, - const std::shared_ptr& configs, - ISchedulerCallback& schedulerCallback, - std::unique_ptr layerHistory, Options options) - : mOptions(options), - mVsyncSchedule(std::move(schedule)), - mLayerHistory(std::move(layerHistory)), - mSchedulerCallback(schedulerCallback), - mPredictedVsyncTracer( - base::GetBoolProperty("debug.sf.show_predicted_vsync", false) - ? std::make_unique(*mVsyncSchedule.dispatch) - : nullptr) { - setRefreshRateConfigs(configs); - mSchedulerCallback.setVsyncEnabled(false); -} - Scheduler::~Scheduler() { // Ensure the OneShotTimer threads are joined before we start destroying state. mDisplayPowerTimer.reset(); @@ -170,7 +148,7 @@ Scheduler::~Scheduler() { mRefreshRateConfigs.reset(); } -Scheduler::VsyncSchedule Scheduler::createVsyncSchedule(bool supportKernelTimer) { +void Scheduler::createVsyncSchedule(bool supportKernelTimer) { auto clock = std::make_unique(); auto tracker = createVSyncTracker(); auto dispatch = createVSyncDispatch(*tracker); @@ -180,11 +158,11 @@ Scheduler::VsyncSchedule Scheduler::createVsyncSchedule(bool supportKernelTimer) auto controller = std::make_unique(std::move(clock), *tracker, pendingFenceLimit, supportKernelTimer); - return {std::move(controller), std::move(tracker), std::move(dispatch)}; -} + mVsyncSchedule = {std::move(controller), std::move(tracker), std::move(dispatch)}; -std::unique_ptr Scheduler::createLayerHistory() { - return std::make_unique(); + if (base::GetBoolProperty("debug.sf.show_predicted_vsync", false)) { + mPredictedVsyncTracer = std::make_unique(*mVsyncSchedule.dispatch); + } } std::unique_ptr Scheduler::makePrimaryDispSyncSource( @@ -594,11 +572,11 @@ void Scheduler::registerLayer(Layer* layer) { // If the content detection feature is off, we still keep the layer history, // since we use it for other features (like Frame Rate API), so layers // still need to be registered. - mLayerHistory->registerLayer(layer, voteType); + mLayerHistory.registerLayer(layer, voteType); } void Scheduler::deregisterLayer(Layer* layer) { - mLayerHistory->deregisterLayer(layer); + mLayerHistory.deregisterLayer(layer); } void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime, @@ -608,11 +586,11 @@ void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime, if (!mRefreshRateConfigs->canSwitch()) return; } - mLayerHistory->record(layer, presentTime, systemTime(), updateType); + mLayerHistory.record(layer, presentTime, systemTime(), updateType); } void Scheduler::setModeChangePending(bool pending) { - mLayerHistory->setModeChangePending(pending); + mLayerHistory.setModeChangePending(pending); } void Scheduler::chooseRefreshRateForContent() { @@ -625,7 +603,7 @@ void Scheduler::chooseRefreshRateForContent() { const auto refreshRateConfigs = holdRefreshRateConfigs(); scheduler::LayerHistory::Summary summary = - mLayerHistory->summarize(*refreshRateConfigs, systemTime()); + mLayerHistory.summarize(*refreshRateConfigs, systemTime()); scheduler::RefreshRateConfigs::GlobalSignals consideredSignals; DisplayModePtr newMode; bool frameRateChanged; @@ -686,7 +664,7 @@ void Scheduler::setDisplayPowerState(bool normal) { // Display Power event will boost the refresh rate to performance. // Clear Layer History to get fresh FPS detection - mLayerHistory->clear(); + mLayerHistory.clear(); } void Scheduler::kernelIdleTimerCallback(TimerState state) { @@ -730,7 +708,7 @@ void Scheduler::touchTimerCallback(TimerState state) { // NOTE: Instead of checking all the layers, we should be checking the layer // that is currently on top. b/142507166 will give us this capability. if (handleTimerStateChanged(&mFeatures.touch, touch)) { - mLayerHistory->clear(); + mLayerHistory.clear(); } ATRACE_INT("TouchState", static_cast(touch)); } @@ -747,7 +725,7 @@ void Scheduler::dump(std::string& result) const { mTouchTimer ? mTouchTimer->dump().c_str() : "off"); StringAppendF(&result, "+ Content detection: %s %s\n\n", toContentDetectionString(mOptions.useContentDetection), - mLayerHistory ? mLayerHistory->dump().c_str() : "(no layer history)"); + mLayerHistory.dump().c_str()); { std::lock_guard lock(mFrameRateOverridesLock); @@ -911,7 +889,7 @@ void Scheduler::onPostComposition(nsecs_t presentTime) { } void Scheduler::onActiveDisplayAreaChanged(uint32_t displayArea) { - mLayerHistory->setDisplayArea(displayArea); + mLayerHistory.setDisplayArea(displayArea); } void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverride) { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 8397738160..8204abccf9 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -75,9 +75,17 @@ public: using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; using ModeEvent = scheduler::RefreshRateConfigEvent; - Scheduler(const std::shared_ptr&, ISchedulerCallback&); + struct Options { + // Whether to use content detection at all. + bool useContentDetection = false; + }; + + Scheduler(ISchedulerCallback&, Options); ~Scheduler(); + void createVsyncSchedule(bool supportKernelIdleTimer); + void startTimers(); + using ConnectionHandle = scheduler::ConnectionHandle; ConnectionHandle createConnection(const char* connectionName, frametimeline::TokenManager*, std::chrono::nanoseconds workDuration, @@ -213,27 +221,12 @@ private: enum class TimerState { Reset, Expired }; enum class TouchState { Inactive, Active }; - struct Options { - // Whether to use content detection at all. - bool useContentDetection; - }; - struct VsyncSchedule { std::unique_ptr controller; std::unique_ptr tracker; std::unique_ptr dispatch; }; - // Unlike the testing constructor, this creates the VsyncSchedule, LayerHistory, and timers. - Scheduler(const std::shared_ptr&, ISchedulerCallback&, Options); - - // Used by tests to inject mocks. - Scheduler(VsyncSchedule, const std::shared_ptr&, - ISchedulerCallback&, std::unique_ptr, Options); - - static VsyncSchedule createVsyncSchedule(bool supportKernelIdleTimer); - static std::unique_ptr createLayerHistory(); - // Create a connection on the given EventThread. ConnectionHandle createConnection(std::unique_ptr); sp createConnectionInternal( @@ -297,7 +290,7 @@ private: VsyncSchedule mVsyncSchedule; // Used to choose refresh rate if content detection is enabled. - std::unique_ptr mLayerHistory; + LayerHistory mLayerHistory; // Timer used to monitor touch events. std::optional mTouchTimer; @@ -338,7 +331,7 @@ private: GUARDED_BY(mVsyncTimelineLock); static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms; - const std::unique_ptr mPredictedVsyncTracer; + std::unique_ptr mPredictedVsyncTracer; // The frame rate override lists need their own mutex as they are being read // by SurfaceFlinger, Scheduler and EventThread (as a callback) to prevent deadlocks diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c2dcd70166..34629a29c7 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3149,8 +3149,19 @@ void SurfaceFlinger::initScheduler(const sp& display) { mVsyncConfiguration = getFactory().createVsyncConfiguration(currRefreshRate); mVsyncModulator = sp::make(mVsyncConfiguration->getCurrentConfigs()); - // start the EventThread - mScheduler = getFactory().createScheduler(display->holdRefreshRateConfigs(), *this); + const Scheduler::Options options = { + .useContentDetection = sysprop::use_content_detection_for_refresh_rate(false)}; + + mScheduler = std::make_unique(static_cast(*this), options); + { + auto configs = display->holdRefreshRateConfigs(); + mScheduler->createVsyncSchedule(configs->supportsKernelIdleTimer()); + mScheduler->setRefreshRateConfigs(std::move(configs)); + } + + setVsyncEnabled(false); + mScheduler->startTimers(); + const auto configs = mVsyncConfiguration->getCurrentConfigs(); const nsecs_t vsyncPeriod = currRefreshRate.getPeriodNsecs(); mAppConnectionHandle = diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp index 9a2f9107c3..ae21fccc2d 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp @@ -64,12 +64,6 @@ std::unique_ptr DefaultFactory::createVsyncConfig } } -std::unique_ptr DefaultFactory::createScheduler( - const std::shared_ptr& refreshRateConfigs, - ISchedulerCallback& callback) { - return std::make_unique(std::move(refreshRateConfigs), callback); -} - sp DefaultFactory::createSurfaceInterceptor() { return new android::impl::SurfaceInterceptor(); } diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h index 2be09ee788..4f70979412 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h @@ -30,8 +30,6 @@ public: std::unique_ptr createMessageQueue(ICompositor&) override; std::unique_ptr createVsyncConfiguration( Fps currentRefreshRate) override; - std::unique_ptr createScheduler( - const std::shared_ptr&, ISchedulerCallback&) override; sp createSurfaceInterceptor() override; sp createStartPropertySetThread(bool timestampPropertyValue) override; sp createDisplayDevice(DisplayDeviceCreationArgs&) override; diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index bca533b794..a1bf9feacc 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -80,8 +80,6 @@ public: virtual std::unique_ptr createMessageQueue(ICompositor&) = 0; virtual std::unique_ptr createVsyncConfiguration( Fps currentRefreshRate) = 0; - virtual std::unique_ptr createScheduler( - const std::shared_ptr&, ISchedulerCallback&) = 0; virtual sp createSurfaceInterceptor() = 0; virtual sp createStartPropertySetThread( diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 40ef6e702d..daa6543c32 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -145,9 +145,6 @@ public: mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), std::move(eventThread), std::move(sfEventThread), kCallback, kHasMultipleConfigs); - - // Layer history should be created if there are multiple configs. - ASSERT_TRUE(mFlinger.scheduler()->hasLayerHistory()); } void setupForceGeometryDirty() { @@ -843,7 +840,7 @@ struct BaseLayerVariant { sp layer = factory(); // Layer should be registered with scheduler. - EXPECT_EQ(1, test->mFlinger.scheduler()->layerHistorySize()); + EXPECT_EQ(1u, test->mFlinger.scheduler()->layerHistorySize()); Mock::VerifyAndClear(test->mComposer); Mock::VerifyAndClear(test->mRenderEngine); @@ -888,7 +885,7 @@ struct BaseLayerVariant { // Layer should be unregistered with scheduler. test->mFlinger.commit(); - EXPECT_EQ(0, test->mFlinger.scheduler()->layerHistorySize()); + EXPECT_EQ(0u, test->mFlinger.scheduler()->layerHistorySize()); } }; diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index e8795fea22..4993a2d8bc 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -59,10 +59,8 @@ protected: LayerHistoryTest() { mFlinger.resetScheduler(mScheduler); } - void SetUp() override { ASSERT_TRUE(mScheduler->hasLayerHistory()); } - - LayerHistory& history() { return *mScheduler->mutableLayerHistory(); } - const LayerHistory& history() const { return *mScheduler->mutableLayerHistory(); } + LayerHistory& history() { return mScheduler->mutableLayerHistory(); } + const LayerHistory& history() const { return mScheduler->mutableLayerHistory(); } LayerHistory::Summary summarizeLayerHistory(nsecs_t now) { return history().summarize(*mScheduler->refreshRateConfigs(), now); diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 599b235ff2..e558f3b700 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -68,14 +68,6 @@ protected: std::make_shared(DisplayModes{mode60}, mode60->getId()); mock::SchedulerCallback mSchedulerCallback; - - // The scheduler should initially disable VSYNC. - struct ExpectDisableVsync { - ExpectDisableVsync(mock::SchedulerCallback& callback) { - EXPECT_CALL(callback, setVsyncEnabled(false)).Times(1); - } - } mExpectDisableVsync{mSchedulerCallback}; - TestableScheduler* mScheduler = new TestableScheduler{mConfigs, mSchedulerCallback}; Scheduler::ConnectionHandle mConnectionHandle; @@ -166,9 +158,9 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentIsNoopWhenModeSwitchingIsNotSup sp layer = sp::make(mFlinger.flinger()); // recordLayerHistory should be a noop - ASSERT_EQ(static_cast(0), mScheduler->getNumActiveLayers()); + ASSERT_EQ(0u, mScheduler->getNumActiveLayers()); mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer); - ASSERT_EQ(static_cast(0), mScheduler->getNumActiveLayers()); + ASSERT_EQ(0u, mScheduler->getNumActiveLayers()); constexpr bool kPowerStateNormal = true; mScheduler->setDisplayPowerState(kPowerStateNormal); @@ -181,17 +173,17 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentIsNoopWhenModeSwitchingIsNotSup } TEST_F(SchedulerTest, updateDisplayModes) { - ASSERT_EQ(static_cast(0), mScheduler->layerHistorySize()); + ASSERT_EQ(0u, mScheduler->layerHistorySize()); sp layer = sp::make(mFlinger.flinger()); - ASSERT_EQ(static_cast(1), mScheduler->layerHistorySize()); + ASSERT_EQ(1u, mScheduler->layerHistorySize()); mScheduler->setRefreshRateConfigs( std::make_shared(DisplayModes{mode60, mode120}, mode60->getId())); - ASSERT_EQ(static_cast(0), mScheduler->getNumActiveLayers()); + ASSERT_EQ(0u, mScheduler->getNumActiveLayers()); mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer); - ASSERT_EQ(static_cast(1), mScheduler->getNumActiveLayers()); + ASSERT_EQ(1u, mScheduler->getNumActiveLayers()); } TEST_F(SchedulerTest, testDispatchCachedReportedMode) { diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index d0211780ab..d9c6bfb7ec 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -454,20 +454,16 @@ TEST_P(SetFrameRateTest, SetOnParentActivatesTree) { parent->setFrameRate(FRAME_RATE_VOTE1); commitTransaction(); - mFlinger.mutableScheduler() - .mutableLayerHistory() - ->record(parent.get(), 0, 0, LayerHistory::LayerUpdateType::Buffer); - mFlinger.mutableScheduler() - .mutableLayerHistory() - ->record(child.get(), 0, 0, LayerHistory::LayerUpdateType::Buffer); - - const auto layerHistorySummary = - mFlinger.mutableScheduler() - .mutableLayerHistory() - ->summarize(*mFlinger.mutableScheduler().refreshRateConfigs(), 0); - ASSERT_EQ(2u, layerHistorySummary.size()); - EXPECT_EQ(FRAME_RATE_VOTE1.rate, layerHistorySummary[0].desiredRefreshRate); - EXPECT_EQ(FRAME_RATE_VOTE1.rate, layerHistorySummary[1].desiredRefreshRate); + auto& history = mFlinger.mutableScheduler().mutableLayerHistory(); + history.record(parent.get(), 0, 0, LayerHistory::LayerUpdateType::Buffer); + history.record(child.get(), 0, 0, LayerHistory::LayerUpdateType::Buffer); + + const auto configs = mFlinger.mutableScheduler().refreshRateConfigs(); + const auto summary = history.summarize(*configs, 0); + + ASSERT_EQ(2u, summary.size()); + EXPECT_EQ(FRAME_RATE_VOTE1.rate, summary[0].desiredRefreshRate); + EXPECT_EQ(FRAME_RATE_VOTE1.rate, summary[1].desiredRefreshRate); } TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) { diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 1d21bd43e3..1b850fc055 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -32,19 +32,20 @@ namespace android { class TestableScheduler : public Scheduler { public: - TestableScheduler(const std::shared_ptr& refreshRateConfigs, + TestableScheduler(std::shared_ptr configs, ISchedulerCallback& callback) : TestableScheduler(std::make_unique(), - std::make_unique(), refreshRateConfigs, + std::make_unique(), std::move(configs), callback) {} TestableScheduler(std::unique_ptr vsyncController, std::unique_ptr vsyncTracker, - const std::shared_ptr& refreshRateConfigs, + std::shared_ptr configs, ISchedulerCallback& callback) - : Scheduler({std::move(vsyncController), std::move(vsyncTracker), nullptr}, - refreshRateConfigs, callback, createLayerHistory(), - {.useContentDetection = true}) {} + : Scheduler(callback, {.useContentDetection = true}) { + mVsyncSchedule = {std::move(vsyncController), std::move(vsyncTracker), nullptr}; + setRefreshRateConfigs(std::move(configs)); + } // Used to inject mock event thread. ConnectionHandle createConnection(std::unique_ptr eventThread) { @@ -58,22 +59,13 @@ public: auto& mutablePrimaryHWVsyncEnabled() { return mPrimaryHWVsyncEnabled; } auto& mutableHWVsyncAvailable() { return mHWVsyncAvailable; } - bool hasLayerHistory() const { return static_cast(mLayerHistory); } - - auto* mutableLayerHistory() { return mLayerHistory.get(); } + auto& mutableLayerHistory() { return mLayerHistory; } - size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS { - if (!mLayerHistory) return 0; - return mutableLayerHistory()->mLayerInfos.size(); - } + size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS { return mLayerHistory.mLayerInfos.size(); } + size_t getNumActiveLayers() NO_THREAD_SAFETY_ANALYSIS { return mLayerHistory.mActiveLayersEnd; } auto refreshRateConfigs() { return holdRefreshRateConfigs(); } - size_t getNumActiveLayers() NO_THREAD_SAFETY_ANALYSIS { - if (!mLayerHistory) return 0; - return mutableLayerHistory()->mActiveLayersEnd; - } - void replaceTouchTimer(int64_t millis) { if (mTouchTimer) { mTouchTimer.reset(); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 8cca6af355..c2c4a54d60 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -82,11 +82,6 @@ public: return std::make_unique(); } - std::unique_ptr createScheduler( - const std::shared_ptr&, ISchedulerCallback&) override { - return nullptr; - } - sp createSurfaceInterceptor() override { return new android::impl::SurfaceInterceptor(); } -- cgit v1.2.3-59-g8ed1b From 8f53d3a5242e9ed3d56aa7e85bb1772be31b24e9 Mon Sep 17 00:00:00 2001 From: ramindani Date: Tue, 9 Nov 2021 18:57:03 +0000 Subject: ATRACE when we auto latch unsignaled. BUG: 198189193 Test: Did the manual test and atest libsurfaceflinger_unittest atest MockFence_test atest libgui_test Change-Id: I378ce593494f2f08baf51b8b508fe408e7a03445 --- services/surfaceflinger/SurfaceFlinger.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 45e8d04ff9..21efa6e988 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3557,10 +3557,13 @@ bool SurfaceFlinger::allowedLatchUnsignaled() { bool SurfaceFlinger::checkTransactionCanLatchUnsignaled(const TransactionState& transaction) { if (transaction.states.size() == 1) { const auto& state = transaction.states.begin()->state; - return (state.flags & ~layer_state_t::eBufferChanged) == 0 && - state.bufferData.flags.test(BufferData::BufferDataChange::fenceChanged) && - state.bufferData.acquireFence && - state.bufferData.acquireFence->getStatus() == Fence::Status::Unsignaled; + if ((state.flags & ~layer_state_t::eBufferChanged) == 0 && + state.bufferData.flags.test(BufferData::BufferDataChange::fenceChanged) && + state.bufferData.acquireFence && + state.bufferData.acquireFence->getStatus() == Fence::Status::Unsignaled) { + ATRACE_NAME("transactionCanLatchUnsignaled"); + return true; + } } return false; } -- cgit v1.2.3-59-g8ed1b From a1c4c829a1ac5fd2a5ae583424fd35ae7a9a292c Mon Sep 17 00:00:00 2001 From: chaviw Date: Wed, 10 Nov 2021 18:11:58 -0600 Subject: Rename nextTransaction to syncTransaction The variable nextTransaction is abigious and doesn't represent its purpose. Rename to syncTransaction Test: BLASTBufferQueueTest Bug: 200285149 Change-Id: I1c1e151a63e88127178a92a369e82bcc6770ab90 --- libs/gui/BLASTBufferQueue.cpp | 28 ++++++------- libs/gui/include/gui/BLASTBufferQueue.h | 4 +- libs/gui/tests/BLASTBufferQueue_test.cpp | 68 ++++++++++++++++---------------- 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 9080822f92..e9149f3a3e 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -138,7 +138,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp= mLastAcquiredFrameNumber) { mWaitForTransactionCallback = false; flushShadowQueue(); @@ -420,7 +420,7 @@ void BLASTBufferQueue::releaseBufferCallback( mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence); mSubmitted.erase(it); // Don't process the transactions here if mWaitForTransactionCallback is set. Instead, let - // onFrameAvailable handle processing them since it will merge with the nextTransaction. + // onFrameAvailable handle processing them since it will merge with the syncTransaction. if (!mWaitForTransactionCallback) { acquireNextBufferLocked(std::nullopt); } @@ -593,15 +593,15 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { ATRACE_CALL(); std::unique_lock _lock{mMutex}; - const bool nextTransactionSet = mNextTransaction != nullptr; - BQA_LOGV("onFrameAvailable-start nextTransactionSet=%s", boolToString(nextTransactionSet)); - if (nextTransactionSet) { + const bool syncTransactionSet = mSyncTransaction != nullptr; + BQA_LOGV("onFrameAvailable-start syncTransactionSet=%s", boolToString(syncTransactionSet)); + if (syncTransactionSet) { if (mWaitForTransactionCallback) { // We are waiting on a previous sync's transaction callback so allow another sync // transaction to proceed. // // We need to first flush out the transactions that were in between the two syncs. - // We do this by merging them into mNextTransaction so any buffer merging will get + // We do this by merging them into mSyncTransaction so any buffer merging will get // a release callback invoked. The release callback will be async so we need to wait // on max acquired to make sure we have the capacity to acquire another buffer. if (maxBuffersAcquired(false /* includeExtraAcquire */)) { @@ -625,12 +625,12 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { ATRACE_INT(mQueuedBufferTrace.c_str(), mNumFrameAvailable + mNumAcquired - mPendingRelease.size()); - BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s", item.mFrameNumber, - boolToString(nextTransactionSet)); + BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " syncTransactionSet=%s", item.mFrameNumber, + boolToString(syncTransactionSet)); - if (nextTransactionSet) { - acquireNextBufferLocked(std::move(mNextTransaction)); - mNextTransaction = nullptr; + if (syncTransactionSet) { + acquireNextBufferLocked(std::move(mSyncTransaction)); + mSyncTransaction = nullptr; mWaitForTransactionCallback = true; } else if (!mWaitForTransactionCallback) { acquireNextBufferLocked(std::nullopt); @@ -652,9 +652,9 @@ void BLASTBufferQueue::onFrameCancelled(const uint64_t bufferId) { mDequeueTimestamps.erase(bufferId); }; -void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) { +void BLASTBufferQueue::setSyncTransaction(SurfaceComposerClient::Transaction* t) { std::lock_guard _lock{mMutex}; - mNextTransaction = t; + mSyncTransaction = t; } bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 4a63544464..f718de8c57 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -94,7 +94,7 @@ public: const std::vector& stats); void releaseBufferCallback(const ReleaseCallbackId& id, const sp& releaseFence, std::optional currentMaxAcquiredBufferCount); - void setNextTransaction(SurfaceComposerClient::Transaction *t); + void setSyncTransaction(SurfaceComposerClient::Transaction* t); void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber); void applyPendingTransactions(uint64_t frameNumber); @@ -208,7 +208,7 @@ private: sp mProducer; sp mBufferItemConsumer; - SurfaceComposerClient::Transaction* mNextTransaction GUARDED_BY(mMutex); + SurfaceComposerClient::Transaction* mSyncTransaction GUARDED_BY(mMutex); std::vector> mPendingTransactions GUARDED_BY(mMutex); diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 8607e1d83c..194757fe6b 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -109,15 +109,15 @@ public: mBlastBufferQueueAdapter->update(sc, width, height, PIXEL_FORMAT_RGBA_8888); } - void setNextTransaction(Transaction* next) { - mBlastBufferQueueAdapter->setNextTransaction(next); + void setSyncTransaction(Transaction* sync) { + mBlastBufferQueueAdapter->setSyncTransaction(sync); } int getWidth() { return mBlastBufferQueueAdapter->mSize.width; } int getHeight() { return mBlastBufferQueueAdapter->mSize.height; } - Transaction* getNextTransaction() { return mBlastBufferQueueAdapter->mNextTransaction; } + Transaction* getSyncTransaction() { return mBlastBufferQueueAdapter->mSyncTransaction; } sp getIGraphicBufferProducer() { return mBlastBufferQueueAdapter->getIGraphicBufferProducer(); @@ -337,7 +337,7 @@ TEST_F(BLASTBufferQueueTest, CreateBLASTBufferQueue) { ASSERT_EQ(mSurfaceControl, adapter.getSurfaceControl()); ASSERT_EQ(mDisplayWidth, adapter.getWidth()); ASSERT_EQ(mDisplayHeight, adapter.getHeight()); - ASSERT_EQ(nullptr, adapter.getNextTransaction()); + ASSERT_EQ(nullptr, adapter.getSyncTransaction()); } TEST_F(BLASTBufferQueueTest, Update) { @@ -358,11 +358,11 @@ TEST_F(BLASTBufferQueueTest, Update) { ASSERT_EQ(mDisplayHeight / 2, height); } -TEST_F(BLASTBufferQueueTest, SetNextTransaction) { +TEST_F(BLASTBufferQueueTest, SetSyncTransaction) { BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); - Transaction next; - adapter.setNextTransaction(&next); - ASSERT_EQ(&next, adapter.getNextTransaction()); + Transaction sync; + adapter.setSyncTransaction(&sync); + ASSERT_EQ(&sync, adapter.getSyncTransaction()); } TEST_F(BLASTBufferQueueTest, DISABLED_onFrameAvailable_ApplyDesiredPresentTime) { @@ -801,8 +801,8 @@ TEST_F(BLASTBufferQueueTest, SyncThenNoSync) { sp igbProducer; setUpProducer(adapter, igbProducer); - Transaction next; - adapter.setNextTransaction(&next); + Transaction sync; + adapter.setSyncTransaction(&sync); queueBuffer(igbProducer, 0, 255, 0, 0); // queue non sync buffer, so this one should get blocked @@ -811,7 +811,7 @@ TEST_F(BLASTBufferQueueTest, SyncThenNoSync) { queueBuffer(igbProducer, r, g, b, presentTimeDelay); CallbackHelper transactionCallback; - next.addTransactionCompletedCallback(transactionCallback.function, + sync.addTransactionCompletedCallback(transactionCallback.function, transactionCallback.getContext()) .apply(); @@ -841,16 +841,16 @@ TEST_F(BLASTBufferQueueTest, MultipleSyncTransactions) { Transaction mainTransaction; - Transaction next; - adapter.setNextTransaction(&next); + Transaction sync; + adapter.setSyncTransaction(&sync); queueBuffer(igbProducer, 0, 255, 0, 0); - mainTransaction.merge(std::move(next)); + mainTransaction.merge(std::move(sync)); - adapter.setNextTransaction(&next); + adapter.setSyncTransaction(&sync); queueBuffer(igbProducer, r, g, b, 0); - mainTransaction.merge(std::move(next)); + mainTransaction.merge(std::move(sync)); // Expect 1 buffer to be released even before sending to SurfaceFlinger mProducerListener->waitOnNumberReleased(1); @@ -881,24 +881,24 @@ TEST_F(BLASTBufferQueueTest, MultipleSyncTransactionWithNonSync) { Transaction mainTransaction; - Transaction next; + Transaction sync; // queue a sync transaction - adapter.setNextTransaction(&next); + adapter.setSyncTransaction(&sync); queueBuffer(igbProducer, 0, 255, 0, 0); - mainTransaction.merge(std::move(next)); + mainTransaction.merge(std::move(sync)); - // queue another buffer without setting next transaction + // queue another buffer without setting sync transaction queueBuffer(igbProducer, 0, 0, 255, 0); // queue another sync transaction - adapter.setNextTransaction(&next); + adapter.setSyncTransaction(&sync); queueBuffer(igbProducer, r, g, b, 0); // Expect 1 buffer to be released because the non sync transaction should merge // with the sync mProducerListener->waitOnNumberReleased(1); - mainTransaction.merge(std::move(next)); + mainTransaction.merge(std::move(sync)); // Expect 2 buffers to be released due to merging the two syncs. mProducerListener->waitOnNumberReleased(2); @@ -929,26 +929,26 @@ TEST_F(BLASTBufferQueueTest, MultipleSyncRunOutOfBuffers) { Transaction mainTransaction; - Transaction next; + Transaction sync; // queue a sync transaction - adapter.setNextTransaction(&next); + adapter.setSyncTransaction(&sync); queueBuffer(igbProducer, 0, 255, 0, 0); - mainTransaction.merge(std::move(next)); + mainTransaction.merge(std::move(sync)); - // queue a few buffers without setting next transaction + // queue a few buffers without setting sync transaction queueBuffer(igbProducer, 0, 0, 255, 0); queueBuffer(igbProducer, 0, 0, 255, 0); queueBuffer(igbProducer, 0, 0, 255, 0); // queue another sync transaction - adapter.setNextTransaction(&next); + adapter.setSyncTransaction(&sync); queueBuffer(igbProducer, r, g, b, 0); // Expect 3 buffers to be released because the non sync transactions should merge // with the sync mProducerListener->waitOnNumberReleased(3); - mainTransaction.merge(std::move(next)); + mainTransaction.merge(std::move(sync)); // Expect 4 buffers to be released due to merging the two syncs. mProducerListener->waitOnNumberReleased(4); @@ -986,14 +986,14 @@ TEST_F(BLASTBufferQueueTest, RunOutOfBuffersWaitingOnSF) { // Send a buffer to SF queueBuffer(igbProducer, 0, 255, 0, 0); - Transaction next; + Transaction sync; // queue a sync transaction - adapter.setNextTransaction(&next); + adapter.setSyncTransaction(&sync); queueBuffer(igbProducer, 0, 255, 0, 0); - mainTransaction.merge(std::move(next)); + mainTransaction.merge(std::move(sync)); - // queue a few buffers without setting next transaction + // queue a few buffers without setting sync transaction queueBuffer(igbProducer, 0, 0, 255, 0); queueBuffer(igbProducer, 0, 0, 255, 0); queueBuffer(igbProducer, 0, 0, 255, 0); @@ -1002,13 +1002,13 @@ TEST_F(BLASTBufferQueueTest, RunOutOfBuffersWaitingOnSF) { mainTransaction.apply(); // queue another sync transaction - adapter.setNextTransaction(&next); + adapter.setSyncTransaction(&sync); queueBuffer(igbProducer, r, g, b, 0); // Expect 2 buffers to be released because the non sync transactions should merge // with the sync mProducerListener->waitOnNumberReleased(3); - mainTransaction.merge(std::move(next)); + mainTransaction.merge(std::move(sync)); CallbackHelper transactionCallback; mainTransaction -- cgit v1.2.3-59-g8ed1b From 406c8abeff595432782740345abad06280d18032 Mon Sep 17 00:00:00 2001 From: Bo Liu Date: Wed, 10 Nov 2021 19:20:40 -0500 Subject: Performance hint ndk APIs Test: atest PerformanceHintNativeTestCases Change-Id: I46644adc4e07f668dd82d261da0aabeeb5403e86 --- include/android/performance_hint.h | 164 +++++++++++++++++++++++++++++ include/private/performance_hint_private.h | 116 -------------------- 2 files changed, 164 insertions(+), 116 deletions(-) create mode 100644 include/android/performance_hint.h diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h new file mode 100644 index 0000000000..5fa47f64be --- /dev/null +++ b/include/android/performance_hint.h @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_NATIVE_PERFORMANCE_HINT_H +#define ANDROID_NATIVE_PERFORMANCE_HINT_H + +#include + +/****************************************************************** + * + * IMPORTANT NOTICE: + * + * This file is part of Android's set of stable system headers + * exposed by the Android NDK (Native Development Kit). + * + * Third-party source AND binary code relies on the definitions + * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. + * + * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) + * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS + * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY + * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES + */ + +#include +#include + +__BEGIN_DECLS + +struct APerformanceHintManager; +struct APerformanceHintSession; + +/** + * An opaque type representing a handle to a performance hint manager. + * It must be released after use. + * + *

To use:

    + *
  • Obtain the performance hint manager instance by calling + * {@link APerformanceHint_getManager} function.
  • + *
  • Create an {@link APerformanceHintSession} with + * {@link APerformanceHint_createSession}.
  • + *
  • Get the preferred update rate in nanoseconds with + * {@link APerformanceHint_getPreferredUpdateRateNanos}.
  • + */ +typedef struct APerformanceHintManager APerformanceHintManager; + +/** + * An opaque type representing a handle to a performance hint session. + * A session can only be acquired from a {@link APerformanceHintManager} + * with {@link APerformanceHint_getPreferredUpdateRateNanos}. It must be + * freed with {@link APerformanceHint_closeSession} after use. + * + * A Session represents a group of threads with an inter-related workload such that hints for + * their performance should be considered as a unit. The threads in a given session should be + * long-life and not created or destroyed dynamically. + * + *

    Each session is expected to have a periodic workload with a target duration for each + * cycle. The cycle duration is likely greater than the target work duration to allow other + * parts of the pipeline to run within the available budget. For example, a renderer thread may + * work at 60hz in order to produce frames at the display's frame but have a target work + * duration of only 6ms.

    + * + *

    After each cycle of work, the client is expected to use + * {@link APerformanceHint_reportActualWorkDuration} to report the actual time taken to + * complete.

    + * + *

    To use:

      + *
    • Update a sessions target duration for each cycle of work + * with {@link APerformanceHint_updateTargetWorkDuration}.
    • + *
    • Report the actual duration for the last cycle of work with + * {@link APerformanceHint_reportActualWorkDuration}.
    • + *
    • Release the session instance with + * {@link APerformanceHint_closeSession}.

    + */ +typedef struct APerformanceHintSession APerformanceHintSession; + +/** + * Acquire an instance of the performance hint manager. + * + * @return manager instance on success, nullptr on failure. + */ +APerformanceHintManager* APerformanceHint_getManager() __INTRODUCED_IN(__ANDROID_API_T__); + +/** + * Creates a session for the given set of threads and sets their initial target work + * duration. + * @param manager The performance hint manager instance. + * @param threadIds The list of threads to be associated with this session. They must be part of + * this app's thread group. + * @param size the size of threadIds. + * @param initialTargetWorkDurationNanos The desired duration in nanoseconds for the new session. + * This must be positive. + * @return manager instance on success, nullptr on failure. + */ +APerformanceHintSession* APerformanceHint_createSession( + APerformanceHintManager* manager, + const int32_t* threadIds, size_t size, + int64_t initialTargetWorkDurationNanos) __INTRODUCED_IN(__ANDROID_API_T__); + +/** + * Get preferred update rate information for this device. + * + * @param manager The performance hint manager instance. + * @return the preferred update rate supported by device software. + */ +int64_t APerformanceHint_getPreferredUpdateRateNanos( + APerformanceHintManager* manager) __INTRODUCED_IN(__ANDROID_API_T__); + +/** + * Updates this session's target duration for each cycle of work. + * + * @param session The performance hint session instance to update. + * @param targetDurationNanos the new desired duration in nanoseconds. This must be positive. + * @return 0 on success + * EINVAL if targetDurationNanos is not positive. + * EPIPE if communication with the system service has failed. + */ +int APerformanceHint_updateTargetWorkDuration( + APerformanceHintSession* session, + int64_t targetDurationNanos) __INTRODUCED_IN(__ANDROID_API_T__); + +/** + * Reports the actual duration for the last cycle of work. + * + *

    The system will attempt to adjust the core placement of the threads within the thread + * group and/or the frequency of the core on which they are run to bring the actual duration + * close to the target duration.

    + * + * @param session The performance hint session instance to update. + * @param actualDurationNanos how long the thread group took to complete its last task in + * nanoseconds. This must be positive. + * @return 0 on success + * EINVAL if actualDurationNanos is not positive. + * EPIPE if communication with the system service has failed. + */ +int APerformanceHint_reportActualWorkDuration( + APerformanceHintSession* session, + int64_t actualDurationNanos) __INTRODUCED_IN(__ANDROID_API_T__); + +/** + * Release the performance hint manager pointer acquired via + * {@link APerformanceHint_createSession}. + * + * @param session The performance hint session instance to release. + */ +void APerformanceHint_closeSession( + APerformanceHintSession* session) __INTRODUCED_IN(__ANDROID_API_T__); + +__END_DECLS + +#endif // ANDROID_NATIVE_PERFORMANCE_HINT_H diff --git a/include/private/performance_hint_private.h b/include/private/performance_hint_private.h index 5832bf49bd..f27f5f150f 100644 --- a/include/private/performance_hint_private.h +++ b/include/private/performance_hint_private.h @@ -17,124 +17,8 @@ #ifndef ANDROID_PRIVATE_NATIVE_PERFORMANCE_HINT_PRIVATE_H #define ANDROID_PRIVATE_NATIVE_PERFORMANCE_HINT_PRIVATE_H -#include - __BEGIN_DECLS -struct APerformanceHintManager; -struct APerformanceHintSession; - -/** - * An opaque type representing a handle to a performance hint manager. - * It must be released after use. - * - *

    To use:

      - *
    • Obtain the performance hint manager instance by calling - * {@link APerformanceHint_getManager} function.
    • - *
    • Create an {@link APerformanceHintSession} with - * {@link APerformanceHint_createSession}.
    • - *
    • Get the preferred update rate in nanoseconds with - * {@link APerformanceHint_getPreferredUpdateRateNanos}.
    • - */ -typedef struct APerformanceHintManager APerformanceHintManager; - -/** - * An opaque type representing a handle to a performance hint session. - * A session can only be acquired from a {@link APerformanceHintManager} - * with {@link APerformanceHint_getPreferredUpdateRateNanos}. It must be - * freed with {@link APerformanceHint_closeSession} after use. - * - * A Session represents a group of threads with an inter-related workload such that hints for - * their performance should be considered as a unit. The threads in a given session should be - * long-life and not created or destroyed dynamically. - * - *

      Each session is expected to have a periodic workload with a target duration for each - * cycle. The cycle duration is likely greater than the target work duration to allow other - * parts of the pipeline to run within the available budget. For example, a renderer thread may - * work at 60hz in order to produce frames at the display's frame but have a target work - * duration of only 6ms.

      - * - *

      After each cycle of work, the client is expected to use - * {@link APerformanceHint_reportActualWorkDuration} to report the actual time taken to - * complete.

      - * - *

      To use:

        - *
      • Update a sessions target duration for each cycle of work - * with {@link APerformanceHint_updateTargetWorkDuration}.
      • - *
      • Report the actual duration for the last cycle of work with - * {@link APerformanceHint_reportActualWorkDuration}.
      • - *
      • Release the session instance with - * {@link APerformanceHint_closeSession}.

      - */ -typedef struct APerformanceHintSession APerformanceHintSession; - -/** - * Acquire an instance of the performance hint manager. - * - * @return manager instance on success, nullptr on failure. - */ -APerformanceHintManager* APerformanceHint_getManager(); - -/** - * Creates a session for the given set of threads and sets their initial target work - * duration. - * @param manager The performance hint manager instance. - * @param threadIds The list of threads to be associated with this session. They must be part of - * this app's thread group. - * @param size the size of threadIds. - * @param initialTargetWorkDurationNanos The desired duration in nanoseconds for the new session. - * This must be positive. - * @return manager instance on success, nullptr on failure. - */ -APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager, - const int32_t* threadIds, size_t size, - int64_t initialTargetWorkDurationNanos); - -/** - * Get preferred update rate information for this device. - * - * @param manager The performance hint manager instance. - * @return the preferred update rate supported by device software. - */ -int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager); - -/** - * Updates this session's target duration for each cycle of work. - * - * @param session The performance hint session instance to update. - * @param targetDurationNanos the new desired duration in nanoseconds. This must be positive. - * @return 0 on success - * EINVAL if targetDurationNanos is not positive. - * EPIPE if communication with the system service has failed. - */ -int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session, - int64_t targetDurationNanos); - -/** - * Reports the actual duration for the last cycle of work. - * - *

      The system will attempt to adjust the core placement of the threads within the thread - * group and/or the frequency of the core on which they are run to bring the actual duration - * close to the target duration.

      - * - * @param session The performance hint session instance to update. - * @param actualDurationNanos how long the thread group took to complete its last task in - * nanoseconds. This must be positive. - * @return 0 on success - * EINVAL if actualDurationNanos is not positive. - * EPIPE if communication with the system service has failed. - */ -int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session, - int64_t actualDurationNanos); - -/** - * Release the performance hint manager pointer acquired via - * {@link APerformanceHint_createSession}. - * - * @param session The performance hint session instance to release. - */ -void APerformanceHint_closeSession(APerformanceHintSession* session); - /** * For testing only. */ -- cgit v1.2.3-59-g8ed1b From d65a475f377265a1fba322b61dd998a6f11c5031 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Mon, 8 Nov 2021 04:39:24 -0800 Subject: SF: Clean up input info loop Remove the need to loop through all displays for each layer by caching the necessary display info beforehand. Bug: 188939842 Test: presubmit Change-Id: I80d5d09855756011fa1ce8efed841120cf0aab18 --- services/surfaceflinger/SurfaceFlinger.cpp | 48 +++++++++++------------------- services/surfaceflinger/SurfaceFlinger.h | 2 -- 2 files changed, 17 insertions(+), 33 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4770feb6b1..7245f76183 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3044,7 +3044,9 @@ void SurfaceFlinger::updateInputFlinger() { void SurfaceFlinger::notifyWindowInfos() { std::vector windowInfos; std::vector displayInfos; - std::unordered_map displayTransforms; + std::unordered_map> + inputDisplayDetails; for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { if (!display->receivesInput()) { @@ -3052,7 +3054,8 @@ void SurfaceFlinger::notifyWindowInfos() { } const uint32_t layerStackId = display->getLayerStack().id; const auto& [info, transform] = display->getInputInfo(); - const auto& [it, emplaced] = displayTransforms.try_emplace(layerStackId, transform); + const auto& [it, emplaced] = + inputDisplayDetails.try_emplace(layerStackId, display->isSecure(), transform); if (!emplaced) { ALOGE("Multiple displays claim to accept input for the same layer stack: %u", layerStackId); @@ -3064,19 +3067,21 @@ void SurfaceFlinger::notifyWindowInfos() { mDrawingState.traverseInReverseZOrder([&](Layer* layer) { if (!layer->needsInputInfo()) return; - const DisplayDevice* display = ON_MAIN_THREAD(getDisplayWithInputByLayer(layer)).get(); + bool isSecure = true; ui::Transform displayTransform = ui::Transform(); - if (display != nullptr) { - // When calculating the screen bounds we ignore the transparent region since it may - // result in an unwanted offset. - const auto it = displayTransforms.find(display->getLayerStack().id); - if (it != displayTransforms.end()) { - displayTransform = it->second; - } + const uint32_t layerStackId = layer->getLayerStack().id; + const auto it = inputDisplayDetails.find(layerStackId); + if (it != inputDisplayDetails.end()) { + const auto& [secure, transform] = it->second; + isSecure = secure; + displayTransform = transform; + } else { + ALOGE("No input-enabled display found for layer `%s` on layer stack id: %d", + layer->getDebugName(), layerStackId); } - const bool displayIsSecure = !display || display->isSecure(); - windowInfos.push_back(layer->fillInputInfo(displayTransform, displayIsSecure)); + + windowInfos.push_back(layer->fillInputInfo(displayTransform, isSecure)); }); mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos, mInputWindowCommands.syncInputWindows); @@ -4517,25 +4522,6 @@ void SurfaceFlinger::initializeDisplays() { static_cast(schedule([this]() MAIN_THREAD { onInitializeDisplays(); })); } -sp SurfaceFlinger::getDisplayWithInputByLayer(Layer* layer) const { - const auto filter = layer->getOutputFilter(); - sp inputDisplay; - - for (const auto& [_, display] : mDisplays) { - if (!display->receivesInput() || !display->getCompositionDisplay()->includesLayer(filter)) { - continue; - } - // Don't return immediately so that we can log duplicates. - if (inputDisplay) { - ALOGE("Multiple displays claim to accept input for the same layer stack: %u", - filter.layerStack.id); - continue; - } - inputDisplay = display; - } - return inputDisplay; -} - void SurfaceFlinger::setPowerModeInternal(const sp& display, hal::PowerMode mode) { if (display->isVirtual()) { ALOGE("%s: Invalid operation on virtual display", __FUNCTION__); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index bf628dc309..23e40c2118 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -897,8 +897,6 @@ private: // region of all screens presenting this layer stack. void invalidateLayerStack(const sp& layer, const Region& dirty); - sp getDisplayWithInputByLayer(Layer* layer) const REQUIRES(mStateLock); - bool isDisplayActiveLocked(const sp& display) const REQUIRES(mStateLock) { return display->getDisplayToken() == mActiveDisplayToken; } -- cgit v1.2.3-59-g8ed1b From 756b7891d08166ba3323208b28c7c8e0bd2aef2f Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Wed, 4 Aug 2021 12:53:59 -0700 Subject: SF: Move MessageQueue to Scheduler ...as a first step in removing the ISchedulerCallback::scheduleComposite roundtrip, and extracting scheduling logic from SF::{commit,composite}. Bug: 185535769 Test: libsurfaceflinger_unittest Change-Id: I7fb38a1dd7b917e5639b9d58a0d44b32983b689e --- services/surfaceflinger/Scheduler/Scheduler.cpp | 10 +- services/surfaceflinger/Scheduler/Scheduler.h | 28 ++- services/surfaceflinger/SurfaceFlinger.cpp | 278 +++++++++++---------- services/surfaceflinger/SurfaceFlinger.h | 12 +- .../SurfaceFlingerDefaultFactory.cpp | 5 - .../surfaceflinger/SurfaceFlingerDefaultFactory.h | 1 - services/surfaceflinger/SurfaceFlingerFactory.h | 1 - services/surfaceflinger/tests/unittests/Android.bp | 1 - .../tests/unittests/CompositionTest.cpp | 11 +- .../tests/unittests/DisplayTransactionTest.cpp | 1 - .../unittests/DisplayTransactionTestHelpers.h | 2 - .../tests/unittests/SetFrameRateTest.cpp | 21 +- .../unittests/SurfaceFlinger_CreateDisplayTest.cpp | 4 +- .../SurfaceFlinger_DestroyDisplayTest.cpp | 2 +- .../tests/unittests/SurfaceFlinger_HotplugTest.cpp | 4 +- .../SurfaceFlinger_OnInitializeDisplaysTest.cpp | 2 +- .../SurfaceFlinger_SetPowerModeInternalTest.cpp | 2 +- .../tests/unittests/TestableScheduler.h | 18 +- .../tests/unittests/TestableSurfaceFlinger.h | 6 - .../tests/unittests/TransactionApplicationTest.cpp | 13 +- .../unittests/TunnelModeEnabledReporterTest.cpp | 10 +- .../tests/unittests/mock/MockMessageQueue.cpp | 30 --- .../tests/unittests/mock/MockMessageQueue.h | 46 ---- 23 files changed, 223 insertions(+), 285 deletions(-) delete mode 100644 services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp delete mode 100644 services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index f201996394..4d72798086 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -117,8 +117,8 @@ private: } }; -Scheduler::Scheduler(ISchedulerCallback& callback, Options options) - : mOptions(options), mSchedulerCallback(callback) {} +Scheduler::Scheduler(ICompositor& compositor, ISchedulerCallback& callback, Options options) + : impl::MessageQueue(compositor), mOptions(options), mSchedulerCallback(callback) {} void Scheduler::startTimers() { using namespace sysprop; @@ -148,6 +148,12 @@ Scheduler::~Scheduler() { mRefreshRateConfigs.reset(); } +void Scheduler::run() { + while (true) { + waitMessage(); + } +} + void Scheduler::createVsyncSchedule(bool supportKernelTimer) { auto clock = std::make_unique(); auto tracker = createVSyncTracker(); diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 8204abccf9..6d45b5d69b 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -32,6 +33,7 @@ #include "EventThread.h" #include "LayerHistory.h" +#include "MessageQueue.h" #include "OneShotTimer.h" #include "RefreshRateConfigs.h" #include "SchedulerUtils.h" @@ -70,21 +72,41 @@ protected: ~ISchedulerCallback() = default; }; -class Scheduler { +class Scheduler : impl::MessageQueue { + using Impl = impl::MessageQueue; + public: using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; using ModeEvent = scheduler::RefreshRateConfigEvent; struct Options { // Whether to use content detection at all. - bool useContentDetection = false; + bool useContentDetection; }; - Scheduler(ISchedulerCallback&, Options); + Scheduler(ICompositor&, ISchedulerCallback&, Options); ~Scheduler(); void createVsyncSchedule(bool supportKernelIdleTimer); void startTimers(); + void run(); + + using Impl::initVsync; + using Impl::setInjector; + + using Impl::getScheduledFrameTime; + using Impl::setDuration; + + using Impl::scheduleCommit; + using Impl::scheduleComposite; + + // Schedule an asynchronous or synchronous task on the main thread. + template > + [[nodiscard]] std::future schedule(F&& f) { + auto [task, future] = makeTask(std::move(f)); + postMessage(std::move(task)); + return std::move(future); + } using ConnectionHandle = scheduler::ConnectionHandle; ConnectionHandle createConnection(const char* connectionName, frametimeline::TokenManager*, diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d1e24d9b11..48bd54f1d9 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -125,7 +125,6 @@ #include "Scheduler/DispSyncSource.h" #include "Scheduler/EventThread.h" #include "Scheduler/LayerHistory.h" -#include "Scheduler/MessageQueue.h" #include "Scheduler/Scheduler.h" #include "Scheduler/VsyncConfiguration.h" #include "Scheduler/VsyncController.h" @@ -362,7 +361,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) mTimeStats(std::make_shared()), mFrameTracer(mFactory.createFrameTracer()), mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, getpid())), - mEventQueue(mFactory.createMessageQueue(*this)), mCompositionEngine(mFactory.createCompositionEngine()), mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)), mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()), @@ -509,8 +507,8 @@ void SurfaceFlinger::binderDied(const wp&) { // the window manager died on us. prepare its eulogy. mBootFinished = false; - // Sever the link to inputflinger since its gone as well. - static_cast(schedule([=] { mInputFlinger = nullptr; })); + // Sever the link to inputflinger since it's gone as well. + static_cast(mScheduler->schedule([=] { mInputFlinger = nullptr; })); // restore initial conditions (default device unblank, etc) initializeDisplays(); @@ -520,16 +518,7 @@ void SurfaceFlinger::binderDied(const wp&) { } void SurfaceFlinger::run() { - while (true) { - mEventQueue->waitMessage(); - } -} - -template -inline std::future SurfaceFlinger::schedule(F&& f) { - auto [task, future] = makeTask(std::move(f)); - mEventQueue->postMessage(std::move(task)); - return std::move(future); + mScheduler->run(); } sp SurfaceFlinger::createConnection() { @@ -730,7 +719,7 @@ void SurfaceFlinger::bootFinished() { sp input(defaultServiceManager()->getService(String16("inputflinger"))); - static_cast(schedule([=] { + static_cast(mScheduler->schedule([=] { if (input == nullptr) { ALOGE("Failed to link to input service"); } else { @@ -771,7 +760,7 @@ uint32_t SurfaceFlinger::getNewTexture() { if (std::this_thread::get_id() == mMainThreadId) { return genTextures(); } else { - return schedule(genTextures).get(); + return mScheduler->schedule(genTextures).get(); } } @@ -1120,7 +1109,7 @@ status_t SurfaceFlinger::setActiveMode(const sp& displayToken, int mode return BAD_VALUE; } - auto future = schedule([=]() -> status_t { + auto future = mScheduler->schedule([=]() -> status_t { const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken)); if (!display) { ALOGE("Attempt to set allowed display modes for invalid display token %p", @@ -1284,7 +1273,7 @@ void SurfaceFlinger::performSetActiveMode() { } void SurfaceFlinger::disableExpensiveRendering() { - schedule([=]() MAIN_THREAD { + auto future = mScheduler->schedule([=]() MAIN_THREAD { ATRACE_CALL(); if (mPowerAdvisor.isUsingExpensiveRendering()) { const auto& displays = ON_MAIN_THREAD(mDisplays); @@ -1293,7 +1282,9 @@ void SurfaceFlinger::disableExpensiveRendering() { mPowerAdvisor.setExpensiveRenderingExpected(display->getId(), kDisable); } } - }).wait(); + }); + + future.wait(); } std::vector SurfaceFlinger::getDisplayColorModes(const DisplayDevice& display) { @@ -1332,7 +1323,7 @@ status_t SurfaceFlinger::setActiveColorMode(const sp& displayToken, Col return BAD_VALUE; } - auto future = schedule([=]() MAIN_THREAD -> status_t { + auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t { const auto display = getDisplayDeviceLocked(displayToken); if (!display) { ALOGE("Attempt to set active color mode %s (%d) for invalid display token %p", @@ -1367,22 +1358,24 @@ status_t SurfaceFlinger::setActiveColorMode(const sp& displayToken, Col } void SurfaceFlinger::setAutoLowLatencyMode(const sp& displayToken, bool on) { - static_cast(schedule([=]() MAIN_THREAD { + const char* const whence = __func__; + static_cast(mScheduler->schedule([=]() MAIN_THREAD { if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { getHwComposer().setAutoLowLatencyMode(*displayId, on); } else { - ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); + ALOGE("%s: Invalid display token %p", whence, displayToken.get()); } })); } void SurfaceFlinger::setGameContentType(const sp& displayToken, bool on) { - static_cast(schedule([=]() MAIN_THREAD { + const char* const whence = __func__; + static_cast(mScheduler->schedule([=]() MAIN_THREAD { if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { const auto type = on ? hal::ContentType::GAME : hal::ContentType::NONE; getHwComposer().setContentType(*displayId, type); } else { - ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); + ALOGE("%s: Invalid display token %p", whence, displayToken.get()); } })); } @@ -1441,17 +1434,18 @@ status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp status_t SurfaceFlinger::setDisplayContentSamplingEnabled(const sp& displayToken, bool enable, uint8_t componentMask, uint64_t maxFrames) { - return schedule([=]() MAIN_THREAD -> status_t { - if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { - return getHwComposer().setDisplayContentSamplingEnabled(*displayId, enable, - componentMask, - maxFrames); - } else { - ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); - return NAME_NOT_FOUND; - } - }) - .get(); + const char* const whence = __func__; + auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t { + if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { + return getHwComposer().setDisplayContentSamplingEnabled(*displayId, enable, + componentMask, maxFrames); + } else { + ALOGE("%s: Invalid display token %p", whence, displayToken.get()); + return NAME_NOT_FOUND; + } + }); + + return future.get(); } status_t SurfaceFlinger::getDisplayedContentSample(const sp& displayToken, @@ -1493,14 +1487,15 @@ status_t SurfaceFlinger::isWideColorDisplay(const sp& displayToken, } status_t SurfaceFlinger::enableVSyncInjections(bool enable) { - schedule([=] { + auto future = mScheduler->schedule([=] { Mutex::Autolock lock(mStateLock); if (const auto handle = mScheduler->enableVSyncInjection(enable)) { - mEventQueue->setInjector(enable ? mScheduler->getEventConnection(handle) : nullptr); + mScheduler->setInjector(enable ? mScheduler->getEventConnection(handle) : nullptr); } - }).wait(); + }); + future.wait(); return NO_ERROR; } @@ -1516,12 +1511,14 @@ status_t SurfaceFlinger::injectVSync(nsecs_t when) { status_t SurfaceFlinger::getLayerDebugInfo(std::vector* outLayers) { outLayers->clear(); - schedule([=] { + auto future = mScheduler->schedule([=] { const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); mDrawingState.traverseInZOrder([&](Layer* layer) { outLayers->push_back(layer->getLayerDebugInfo(display.get())); }); - }).wait(); + }); + + future.wait(); return NO_ERROR; } @@ -1616,7 +1613,8 @@ status_t SurfaceFlinger::setDisplayBrightness(const sp& displayToken, return BAD_VALUE; } - return ftl::chain(schedule([=]() MAIN_THREAD { + const char* const whence = __func__; + return ftl::chain(mScheduler->schedule([=]() MAIN_THREAD { if (const auto display = getDisplayDeviceLocked(displayToken)) { if (enableSdrDimming) { display->getCompositionDisplay() @@ -1626,7 +1624,7 @@ status_t SurfaceFlinger::setDisplayBrightness(const sp& displayToken, return getHwComposer().setDisplayBrightness(display->getPhysicalId(), brightness.displayBrightness); } else { - ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); + ALOGE("%s: Invalid display token %p", whence, displayToken.get()); return ftl::yield(NAME_NOT_FOUND); } })) @@ -1704,7 +1702,7 @@ void SurfaceFlinger::scheduleCommit(FrameHint hint) { mScheduler->resetIdleTimer(); } mPowerAdvisor.notifyDisplayUpdateImminent(); - mEventQueue->scheduleCommit(); + mScheduler->scheduleCommit(); } void SurfaceFlinger::scheduleComposite(FrameHint hint) { @@ -1718,7 +1716,7 @@ void SurfaceFlinger::scheduleRepaint() { } void SurfaceFlinger::scheduleSample() { - static_cast(schedule([this] { sample(); })); + static_cast(mScheduler->schedule([this] { sample(); })); } nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const { @@ -1813,7 +1811,7 @@ void SurfaceFlinger::setVsyncEnabled(bool enabled) { ATRACE_CALL(); // On main thread to avoid race conditions with display power state. - static_cast(schedule([=]() MAIN_THREAD { + static_cast(mScheduler->schedule([=]() MAIN_THREAD { mHWCVsyncPendingState = enabled ? hal::Vsync::ENABLE : hal::Vsync::DISABLE; if (const auto display = getDefaultDisplayDeviceLocked(); @@ -1930,7 +1928,7 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected // fired yet just wait for the next commit. if (mSetActiveModePending) { if (framePending) { - mEventQueue->scheduleCommit(); + mScheduler->scheduleCommit(); return false; } @@ -2058,7 +2056,7 @@ void SurfaceFlinger::composite(nsecs_t frameTime) { const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration; refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration; refreshArgs.previousPresentFence = mPreviousPresentFences[0].fenceTime; - refreshArgs.scheduledFrameTime = mEventQueue->getScheduledFrameTime(); + refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime(); // Store the present time just before calling to the composition engine so we could notify // the scheduler. @@ -2785,7 +2783,7 @@ void SurfaceFlinger::processDisplayRemoved(const wp& displayToken) { mDisplays.erase(displayToken); if (display && display->isVirtual()) { - static_cast(schedule([display = std::move(display)] { + static_cast(mScheduler->schedule([display = std::move(display)] { // Destroy the display without holding the mStateLock. // This is a temporary solution until we can manage transaction queues without // holding the mStateLock. @@ -3128,7 +3126,8 @@ void SurfaceFlinger::initScheduler(const sp& display) { const Scheduler::Options options = { .useContentDetection = sysprop::use_content_detection_for_refresh_rate(false)}; - mScheduler = std::make_unique(static_cast(*this), options); + mScheduler = std::make_unique(static_cast(*this), + static_cast(*this), options); { auto configs = display->holdRefreshRateConfigs(); mScheduler->createVsyncSchedule(configs->supportsKernelIdleTimer()); @@ -3153,8 +3152,8 @@ void SurfaceFlinger::initScheduler(const sp& display) { mInterceptor->saveVSyncEvent(timestamp); }); - mEventQueue->initVsync(mScheduler->getVsyncDispatch(), *mFrameTimeline->getTokenManager(), - configs.late.sfWorkDuration); + mScheduler->initVsync(mScheduler->getVsyncDispatch(), *mFrameTimeline->getTokenManager(), + configs.late.sfWorkDuration); mRegionSamplingThread = new RegionSamplingThread(*this, RegionSamplingThread::EnvironmentTimingTunables()); @@ -3188,7 +3187,7 @@ void SurfaceFlinger::setVsyncConfig(const VsyncModulator::VsyncConfig& config, mScheduler->setDuration(mSfConnectionHandle, /*workDuration=*/std::chrono::nanoseconds(vsyncPeriod), /*readyDuration=*/config.sfWorkDuration); - mEventQueue->setDuration(config.sfWorkDuration); + mScheduler->setDuration(config.sfWorkDuration); } void SurfaceFlinger::doCommitTransactions() { @@ -4459,7 +4458,7 @@ void SurfaceFlinger::onInitializeDisplays() { void SurfaceFlinger::initializeDisplays() { // Async since we may be called from the main thread. - static_cast(schedule([this]() MAIN_THREAD { onInitializeDisplays(); })); + static_cast(mScheduler->schedule([this]() MAIN_THREAD { onInitializeDisplays(); })); } sp SurfaceFlinger::getDisplayWithInputByLayer(Layer* layer) const { @@ -4578,7 +4577,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, hal: } void SurfaceFlinger::setPowerMode(const sp& displayToken, int mode) { - schedule([=]() MAIN_THREAD { + auto future = mScheduler->schedule([=]() MAIN_THREAD { const auto display = getDisplayDeviceLocked(displayToken); if (!display) { ALOGE("Attempt to set power mode %d for invalid display token %p", mode, @@ -4588,7 +4587,9 @@ void SurfaceFlinger::setPowerMode(const sp& displayToken, int mode) { } else { setPowerModeInternal(display, static_cast(mode)); } - }).wait(); + }); + + future.wait(); } status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { @@ -4910,21 +4911,21 @@ void SurfaceFlinger::dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t } LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) { - return schedule([=] { return dumpDrawingStateProto(traceFlags); }).get(); + return mScheduler->schedule([=] { return dumpDrawingStateProto(traceFlags); }).get(); } void SurfaceFlinger::dumpOffscreenLayers(std::string& result) { + auto future = mScheduler->schedule([this] { + std::string result; + for (Layer* offscreenLayer : mOffscreenLayers) { + offscreenLayer->traverse(LayerVector::StateSet::Drawing, + [&](Layer* layer) { layer->dumpCallingUidPid(result); }); + } + return result; + }); + result.append("Offscreen Layers:\n"); - result.append(schedule([this] { - std::string result; - for (Layer* offscreenLayer : mOffscreenLayers) { - offscreenLayer->traverse(LayerVector::StateSet::Drawing, - [&](Layer* layer) { - layer->dumpCallingUidPid(result); - }); - } - return result; - }).get()); + result.append(future.get()); } void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) const { @@ -5343,7 +5344,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r return NO_ERROR; } case 1006: // Force composite immediately. - mEventQueue->scheduleComposite(); + mScheduler->scheduleComposite(); return NO_ERROR; case 1007: // Unused. return NAME_NOT_FOUND; @@ -5455,7 +5456,8 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } case 1021: { // Disable HWC virtual displays const bool enable = data.readInt32() != 0; - static_cast(schedule([this, enable] { enableHalVirtualDisplays(enable); })); + static_cast( + mScheduler->schedule([this, enable] { enableHalVirtualDisplays(enable); })); return NO_ERROR; } case 1022: { // Set saturation boost @@ -5486,7 +5488,8 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r ALOGD("LayerTracing enabled"); tracingEnabledChanged = mLayerTracing.enable(); if (tracingEnabledChanged) { - schedule([&]() MAIN_THREAD { mLayerTracing.notify("start"); }).wait(); + mScheduler->schedule([&]() MAIN_THREAD { mLayerTracing.notify("start"); }) + .wait(); } } else { ALOGD("LayerTracing disabled"); @@ -5588,7 +5591,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r return NO_ERROR; } case 1034: { - schedule([&] { + auto future = mScheduler->schedule([&] { switch (n = data.readInt32()) { case 0: case 1: @@ -5598,7 +5601,9 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r reply->writeBool(ON_MAIN_THREAD(isRefreshRateOverlayEnabled())); } } - }).get(); + }); + + future.wait(); return NO_ERROR; } case 1035: { @@ -5628,32 +5633,36 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r // rates. case 1036: { if (data.readInt32() > 0) { // turn on - return schedule([this] { - const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); - - // This is a little racy, but not in a way that hurts anything. As we - // grab the defaultMode from the display manager policy, we could be - // setting a new display manager policy, leaving us using a stale - // defaultMode. The defaultMode doesn't matter for the override - // policy though, since we set allowGroupSwitching to true, so it's - // not a problem. - scheduler::RefreshRateConfigs::Policy overridePolicy; - overridePolicy.defaultMode = display->refreshRateConfigs() - .getDisplayManagerPolicy() - .defaultMode; - overridePolicy.allowGroupSwitching = true; - constexpr bool kOverridePolicy = true; - return setDesiredDisplayModeSpecsInternal(display, overridePolicy, - kOverridePolicy); - }) + return mScheduler + ->schedule([this] { + const auto display = + ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); + + // This is a little racy, but not in a way that hurts anything. As + // we grab the defaultMode from the display manager policy, we could + // be setting a new display manager policy, leaving us using a stale + // defaultMode. The defaultMode doesn't matter for the override + // policy though, since we set allowGroupSwitching to true, so it's + // not a problem. + scheduler::RefreshRateConfigs::Policy overridePolicy; + overridePolicy.defaultMode = display->refreshRateConfigs() + .getDisplayManagerPolicy() + .defaultMode; + overridePolicy.allowGroupSwitching = true; + constexpr bool kOverridePolicy = true; + return setDesiredDisplayModeSpecsInternal(display, overridePolicy, + kOverridePolicy); + }) .get(); } else { // turn off - return schedule([this] { - const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); - constexpr bool kOverridePolicy = true; - return setDesiredDisplayModeSpecsInternal(display, {}, - kOverridePolicy); - }) + return mScheduler + ->schedule([this] { + const auto display = + ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); + constexpr bool kOverridePolicy = true; + return setDesiredDisplayModeSpecsInternal(display, {}, + kOverridePolicy); + }) .get(); } } @@ -5698,31 +5707,29 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r // Second argument is an optional uint64 - if present, then limits enabling/disabling // caching to a particular physical display case 1040: { - status_t error = - schedule([&] { - n = data.readInt32(); - std::optional inputId = std::nullopt; - if (uint64_t inputDisplayId; - data.readUint64(&inputDisplayId) == NO_ERROR) { - inputId = DisplayId::fromValue(inputDisplayId); - if (!inputId || getPhysicalDisplayToken(*inputId)) { - ALOGE("No display with id: %" PRIu64, inputDisplayId); - return NAME_NOT_FOUND; - } - } - { - Mutex::Autolock lock(mStateLock); - mLayerCachingEnabled = n != 0; - for (const auto& [_, display] : mDisplays) { - if (!inputId || *inputId == display->getPhysicalId()) { - display->enableLayerCaching(mLayerCachingEnabled); - } - } + auto future = mScheduler->schedule([&] { + n = data.readInt32(); + std::optional inputId = std::nullopt; + if (uint64_t inputDisplayId; data.readUint64(&inputDisplayId) == NO_ERROR) { + inputId = DisplayId::fromValue(inputDisplayId); + if (!inputId || getPhysicalDisplayToken(*inputId)) { + ALOGE("No display with id: %" PRIu64, inputDisplayId); + return NAME_NOT_FOUND; + } + } + { + Mutex::Autolock lock(mStateLock); + mLayerCachingEnabled = n != 0; + for (const auto& [_, display] : mDisplays) { + if (!inputId || *inputId == display->getPhysicalId()) { + display->enableLayerCaching(mLayerCachingEnabled); } - return OK; - }).get(); + } + } + return OK; + }); - if (error != OK) { + if (const status_t error = future.get(); error != OK) { return error; } scheduleRepaint(); @@ -5741,7 +5748,7 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { // Update the overlay on the main thread to avoid race conditions with // mRefreshRateConfigs->getCurrentRefreshRate() - static_cast(schedule([=] { + static_cast(mScheduler->schedule([=] { const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); if (!display) { ALOGW("%s: default display is null", __func__); @@ -5756,7 +5763,7 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { const bool timerExpired = mKernelIdleTimerEnabled && expired; if (display->onKernelTimerChanged(desiredModeId, timerExpired)) { - mEventQueue->scheduleCommit(); + mScheduler->scheduleCommit(); } })); } @@ -6148,14 +6155,15 @@ std::shared_future SurfaceFlinger::captureScre const bool supportsProtected = getRenderEngine().supportsProtectedContent(); bool hasProtectedLayer = false; if (allowProtected && supportsProtected) { - hasProtectedLayer = schedule([=]() { - bool protectedLayerFound = false; - traverseLayers([&](Layer* layer) { - protectedLayerFound = protectedLayerFound || - (layer->isVisible() && layer->isProtected()); - }); - return protectedLayerFound; - }).get(); + auto future = mScheduler->schedule([=]() { + bool protectedLayerFound = false; + traverseLayers([&](Layer* layer) { + protectedLayerFound = + protectedLayerFound || (layer->isVisible() && layer->isProtected()); + }); + return protectedLayerFound; + }); + hasProtectedLayer = future.get(); } const uint32_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER | @@ -6186,9 +6194,11 @@ std::shared_future SurfaceFlinger::captureScre bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission(); - auto scheduleResultFuture = schedule([=, - renderAreaFuture = std::move(renderAreaFuture)]() mutable - -> std::shared_future { + auto scheduleResultFuture = mScheduler->schedule([=, + renderAreaFuture = + std::move(renderAreaFuture)]() mutable + -> std::shared_future< + renderengine::RenderEngineResult> { ScreenCaptureResults captureResults; std::unique_ptr renderArea = renderAreaFuture.get(); if (!renderArea) { @@ -6481,7 +6491,7 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecs( return BAD_VALUE; } - auto future = schedule([=]() -> status_t { + auto future = mScheduler->schedule([=]() -> status_t { const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken)); if (!display) { ALOGE("Attempt to set desired display modes for invalid display token %p", @@ -6618,7 +6628,7 @@ status_t SurfaceFlinger::setFrameRate(const sp& surface, return BAD_VALUE; } - static_cast(schedule([=] { + static_cast(mScheduler->schedule([=] { Mutex::Autolock lock(mStateLock); if (authenticateSurfaceTextureLocked(surface)) { sp layer = (static_cast(surface.get()))->getLayer(); @@ -6810,7 +6820,7 @@ void SurfaceFlinger::sample() { return; } - mRegionSamplingThread->onCompositionComplete(mEventQueue->getScheduledFrameTime()); + mRegionSamplingThread->onCompositionComplete(mScheduler->getScheduledFrameTime()); } void SurfaceFlinger::onActiveDisplaySizeChanged(const sp& activeDisplay) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8897858831..2deb9cb6bb 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -56,7 +56,6 @@ #include "Fps.h" #include "FrameTracker.h" #include "LayerVector.h" -#include "Scheduler/MessageQueue.h" #include "Scheduler/RefreshRateConfigs.h" #include "Scheduler/RefreshRateStats.h" #include "Scheduler/Scheduler.h" @@ -265,10 +264,6 @@ public: SurfaceFlingerBE& getBE() { return mBE; } const SurfaceFlingerBE& getBE() const { return mBE; } - // Schedule an asynchronous or synchronous task on the main thread. - template > - [[nodiscard]] std::future schedule(F&&); - // Schedule commit of transactions on the main thread ahead of the next VSYNC. void scheduleCommit(FrameHint); // As above, but also force composite regardless if transactions were committed. @@ -1206,14 +1201,9 @@ private: TransactionCallbackInvoker mTransactionCallbackInvoker; - // these are thread safe - std::unique_ptr mEventQueue; + // Thread-safe. FrameTracker mAnimFrameTracker; - // protected by mDestroyedLayerLock; - mutable Mutex mDestroyedLayerLock; - Vector mDestroyedLayers; - // We maintain a pool of pre-generated texture names to hand out to avoid // layer creation needing to run on the main thread (which it would // otherwise need to do to access RenderEngine). diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp index ae21fccc2d..b81b445dad 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp @@ -38,7 +38,6 @@ #include "SurfaceInterceptor.h" #include "DisplayHardware/ComposerHal.h" -#include "Scheduler/MessageQueue.h" #include "Scheduler/Scheduler.h" #include "Scheduler/VsyncConfiguration.h" #include "Scheduler/VsyncController.h" @@ -51,10 +50,6 @@ std::unique_ptr DefaultFactory::createHWComposer(const std::string& return std::make_unique(serviceName); } -std::unique_ptr DefaultFactory::createMessageQueue(ICompositor& compositor) { - return std::make_unique(compositor); -} - std::unique_ptr DefaultFactory::createVsyncConfiguration( Fps currentRefreshRate) { if (property_get_bool("debug.sf.use_phase_offsets_as_durations", false)) { diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h index 4f70979412..501629d4da 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h @@ -27,7 +27,6 @@ public: virtual ~DefaultFactory(); std::unique_ptr createHWComposer(const std::string& serviceName) override; - std::unique_ptr createMessageQueue(ICompositor&) override; std::unique_ptr createVsyncConfiguration( Fps currentRefreshRate) override; sp createSurfaceInterceptor() override; diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index a1bf9feacc..e670f37189 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -77,7 +77,6 @@ class NativeWindowSurface; class Factory { public: virtual std::unique_ptr createHWComposer(const std::string& serviceName) = 0; - virtual std::unique_ptr createMessageQueue(ICompositor&) = 0; virtual std::unique_ptr createVsyncConfiguration( Fps currentRefreshRate) = 0; virtual sp createSurfaceInterceptor() = 0; diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 1ac568066e..3dc6d8b5c1 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -107,7 +107,6 @@ cc_test { "mock/MockEventThread.cpp", "mock/MockFrameTimeline.cpp", "mock/MockFrameTracer.cpp", - "mock/MockMessageQueue.cpp", "mock/MockNativeWindowSurface.cpp", "mock/MockSurfaceInterceptor.cpp", "mock/MockTimeStats.cpp", diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index dffc6c6b84..0c9e6e1ed3 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -45,7 +45,6 @@ #include "mock/DisplayHardware/MockComposer.h" #include "mock/DisplayHardware/MockPowerAdvisor.h" #include "mock/MockEventThread.h" -#include "mock/MockMessageQueue.h" #include "mock/MockTimeStats.h" #include "mock/MockVsyncController.h" #include "mock/system/window/MockNativeWindow.h" @@ -95,7 +94,6 @@ public: ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - mFlinger.mutableEventQueue().reset(mMessageQueue); setupScheduler(); EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _)) @@ -183,7 +181,6 @@ public: Hwc2::mock::Composer* mComposer = nullptr; renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine(); mock::TimeStats* mTimeStats = new mock::TimeStats(); - mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); Hwc2::mock::PowerAdvisor mPowerAdvisor; sp mClientTargetAcquireFence = Fence::NO_FENCE; @@ -539,9 +536,9 @@ struct BaseLayerProperties { ASSERT_EQ(NO_ERROR, err); Mock::VerifyAndClear(test->mRenderEngine); - EXPECT_CALL(*test->mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*test->mFlinger.scheduler(), scheduleCommit()).Times(1); enqueueBuffer(test, layer); - Mock::VerifyAndClearExpectations(test->mMessageQueue); + Mock::VerifyAndClearExpectations(test->mFlinger.scheduler()); bool ignoredRecomputeVisibleRegions; layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, 0); @@ -836,7 +833,7 @@ template struct BaseLayerVariant { template static sp createLayerWithFactory(CompositionTest* test, F factory) { - EXPECT_CALL(*test->mMessageQueue, postMessage(_)).Times(0); + EXPECT_CALL(*test->mFlinger.scheduler(), postMessage(_)).Times(0); sp layer = factory(); @@ -845,7 +842,7 @@ struct BaseLayerVariant { Mock::VerifyAndClear(test->mComposer); Mock::VerifyAndClear(test->mRenderEngine); - Mock::VerifyAndClearExpectations(test->mMessageQueue); + Mock::VerifyAndClearExpectations(test->mFlinger.scheduler()); initLayerDrawingStateAndComputeBounds(test, layer); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 6cb3052053..b1f704a48b 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -50,7 +50,6 @@ DisplayTransactionTest::DisplayTransactionTest() { }); injectMockScheduler(); - mFlinger.mutableEventQueue().reset(mMessageQueue); mFlinger.setupRenderEngine(std::unique_ptr(mRenderEngine)); mFlinger.mutableInterceptor() = mSurfaceInterceptor; diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index 7746e73e7a..de5e9dfb97 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -47,7 +47,6 @@ #include "mock/DisplayHardware/MockComposer.h" #include "mock/DisplayHardware/MockPowerAdvisor.h" #include "mock/MockEventThread.h" -#include "mock/MockMessageQueue.h" #include "mock/MockNativeWindowSurface.h" #include "mock/MockSchedulerCallback.h" #include "mock/MockSurfaceInterceptor.h" @@ -118,7 +117,6 @@ public: // to keep a reference to them for use in setting up call expectations. renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine(); Hwc2::mock::Composer* mComposer = nullptr; - mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); sp mSurfaceInterceptor = new mock::SurfaceInterceptor; mock::VsyncController* mVsyncController = new mock::VsyncController; diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index 84c845d0b1..115a44db4a 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -33,7 +33,6 @@ #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" #include "mock/MockEventThread.h" -#include "mock/MockMessageQueue.h" #include "mock/MockVsyncController.h" namespace android { @@ -112,7 +111,6 @@ protected: void commitTransaction(); TestableSurfaceFlinger mFlinger; - mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); std::vector> mLayers; }; @@ -125,7 +123,6 @@ SetFrameRateTest::SetFrameRateTest() { setupScheduler(); mFlinger.setupComposer(std::make_unique()); - mFlinger.mutableEventQueue().reset(mMessageQueue); } void SetFrameRateTest::addChild(sp layer, sp child) { @@ -172,7 +169,7 @@ void SetFrameRateTest::setupScheduler() { namespace { TEST_P(SetFrameRateTest, SetAndGet) { - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); const auto& layerFactory = GetParam(); @@ -183,7 +180,7 @@ TEST_P(SetFrameRateTest, SetAndGet) { } TEST_P(SetFrameRateTest, SetAndGetParent) { - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); const auto& layerFactory = GetParam(); @@ -208,7 +205,7 @@ TEST_P(SetFrameRateTest, SetAndGetParent) { } TEST_P(SetFrameRateTest, SetAndGetParentAllVote) { - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); const auto& layerFactory = GetParam(); @@ -247,7 +244,7 @@ TEST_P(SetFrameRateTest, SetAndGetParentAllVote) { } TEST_P(SetFrameRateTest, SetAndGetChild) { - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); const auto& layerFactory = GetParam(); @@ -272,7 +269,7 @@ TEST_P(SetFrameRateTest, SetAndGetChild) { } TEST_P(SetFrameRateTest, SetAndGetChildAllVote) { - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); const auto& layerFactory = GetParam(); @@ -311,7 +308,7 @@ TEST_P(SetFrameRateTest, SetAndGetChildAllVote) { } TEST_P(SetFrameRateTest, SetAndGetChildAddAfterVote) { - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); const auto& layerFactory = GetParam(); @@ -341,7 +338,7 @@ TEST_P(SetFrameRateTest, SetAndGetChildAddAfterVote) { } TEST_P(SetFrameRateTest, SetAndGetChildRemoveAfterVote) { - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); const auto& layerFactory = GetParam(); @@ -372,7 +369,7 @@ TEST_P(SetFrameRateTest, SetAndGetChildRemoveAfterVote) { } TEST_P(SetFrameRateTest, SetAndGetParentNotInTree) { - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); const auto& layerFactory = GetParam(); @@ -467,7 +464,7 @@ TEST_P(SetFrameRateTest, SetOnParentActivatesTree) { } TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) { - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); const auto& layerFactory = GetParam(); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp index 8c3034178f..2236db7ab3 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp @@ -52,7 +52,7 @@ TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForNonsecureDisplay) { // Cleanup conditions // Creating the display commits a display transaction. - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); } TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForSecureDisplay) { @@ -87,7 +87,7 @@ TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForSecureDisplay) { // Cleanup conditions // Creating the display commits a display transaction. - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp index 7087fb6568..bcd3222f8a 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp @@ -41,7 +41,7 @@ TEST_F(DestroyDisplayTest, destroyDisplayClearsCurrentStateForDisplay) { EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1); // Destroying the display commits a display transaction. - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); // -------------------------------------------------------------------- // Invocation diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp index 29ff0cd90b..cc979c91c7 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp @@ -39,7 +39,7 @@ TEST_F(HotplugTest, enqueuesEventsForDisplayTransaction) { // Call Expectations // We expect a scheduled commit for the display transaction. - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); // -------------------------------------------------------------------- // Invocation @@ -86,7 +86,7 @@ TEST_F(HotplugTest, processesEnqueuedEventsIfCalledOnMainThread) { // Call Expectations // We expect a scheduled commit for the display transaction. - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); // -------------------------------------------------------------------- // Invocation diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp index e1b44cf549..83b150f93f 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp @@ -47,7 +47,7 @@ TEST_F(OnInitializeDisplaysTest, onInitializeDisplaysSetsUpPrimaryDisplay) { Case::Display::setupHwcGetActiveConfigCallExpectations(this); // We expect a scheduled commit for the display transaction. - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp index 6edebd4b3d..ad696aab43 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp @@ -273,7 +273,7 @@ struct DisplayPowerCase { } static void setupRepaintEverythingCallExpectations(DisplayTransactionTest* test) { - EXPECT_CALL(*test->mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*test->mFlinger.scheduler(), scheduleCommit()).Times(1); } static void setupSurfaceInterceptorCallExpectations(DisplayTransactionTest* test, diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 1b850fc055..32ec84853b 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -30,7 +30,7 @@ namespace android { -class TestableScheduler : public Scheduler { +class TestableScheduler : public Scheduler, private ICompositor { public: TestableScheduler(std::shared_ptr configs, ISchedulerCallback& callback) @@ -42,11 +42,19 @@ public: std::unique_ptr vsyncTracker, std::shared_ptr configs, ISchedulerCallback& callback) - : Scheduler(callback, {.useContentDetection = true}) { + : Scheduler(*this, callback, {.useContentDetection = true}) { mVsyncSchedule = {std::move(vsyncController), std::move(vsyncTracker), nullptr}; setRefreshRateConfigs(std::move(configs)); + + ON_CALL(*this, postMessage).WillByDefault([](sp&& handler) { + // Execute task to prevent broken promise exception on destruction. + handler->handleMessage(Message()); + }); } + MOCK_METHOD(void, scheduleCommit, (), (override)); + MOCK_METHOD(void, postMessage, (sp&&), (override)); + // Used to inject mock event thread. ConnectionHandle createConnection(std::unique_ptr eventThread) { return Scheduler::createConnection(std::move(eventThread)); @@ -104,6 +112,12 @@ public: mVsyncSchedule.controller.reset(); mConnections.clear(); } + +private: + // ICompositor overrides: + bool commit(nsecs_t, int64_t, nsecs_t) override { return false; } + void composite(nsecs_t) override {} + void sample() override {} }; } // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index c2c4a54d60..4c5789e47f 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -73,10 +73,6 @@ public: return nullptr; } - std::unique_ptr createMessageQueue(ICompositor& compositor) override { - return std::make_unique(compositor); - } - std::unique_ptr createVsyncConfiguration( Fps /*currentRefreshRate*/) override { return std::make_unique(); @@ -426,7 +422,6 @@ public: auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; } auto& mutableDisplays() { return mFlinger->mDisplays; } auto& mutableDrawingState() { return mFlinger->mDrawingState; } - auto& mutableEventQueue() { return mFlinger->mEventQueue; } auto& mutableGeometryDirty() { return mFlinger->mGeometryDirty; } auto& mutableInterceptor() { return mFlinger->mInterceptor; } auto& mutableMainThreadId() { return mFlinger->mMainThreadId; } @@ -455,7 +450,6 @@ public: mutableDisplays().clear(); mutableCurrentState().displays.clear(); mutableDrawingState().displays.clear(); - mutableEventQueue().reset(); mutableInterceptor().clear(); mFlinger->mScheduler.reset(); mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr()); diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index 8caadfbf85..b3a6a1b264 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -29,7 +29,6 @@ #include "TestableScheduler.h" #include "TestableSurfaceFlinger.h" #include "mock/MockEventThread.h" -#include "mock/MockMessageQueue.h" #include "mock/MockVsyncController.h" namespace android { @@ -46,7 +45,6 @@ public: ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - mFlinger.mutableEventQueue().reset(mMessageQueue); setupScheduler(); } @@ -92,7 +90,6 @@ public: std::unique_ptr mEventThread = std::make_unique(); - mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); mock::VsyncController* mVsyncController = new mock::VsyncController(); mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker(); mock::MockFence* mFenceUnsignaled = new mock::MockFence(); @@ -146,7 +143,7 @@ public: void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) { ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); TransactionInfo transaction; setupSingle(transaction, flags, syncInputWindows, /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, @@ -176,7 +173,7 @@ public: void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) { ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); // first check will see desired present time has not passed, // but afterwards it will look like the desired present time has passed @@ -207,9 +204,9 @@ public: ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); nsecs_t time = systemTime(); if (!syncInputWindows) { - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(2); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(2); } else { - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); } // transaction that should go on the pending thread TransactionInfo transactionA; @@ -454,7 +451,7 @@ public: TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); - EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); TransactionInfo transactionA; // transaction to go on pending queue setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false, diff --git a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp index ade4fbb850..15fea9c6b2 100644 --- a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp +++ b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp @@ -27,7 +27,6 @@ #include "TunnelModeEnabledReporter.h" #include "mock/DisplayHardware/MockComposer.h" #include "mock/MockEventThread.h" -#include "mock/MockMessageQueue.h" namespace android { @@ -69,12 +68,12 @@ protected: TestableSurfaceFlinger mFlinger; Hwc2::mock::Composer* mComposer = nullptr; + sp mTunnelModeEnabledListener = - new TestableTunnelModeEnabledListener(); - sp mTunnelModeEnabledReporter = - new TunnelModeEnabledReporter(); + sp::make(); - mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); + sp mTunnelModeEnabledReporter = + sp::make(); }; TunnelModeEnabledReporterTest::TunnelModeEnabledReporterTest() { @@ -82,7 +81,6 @@ TunnelModeEnabledReporterTest::TunnelModeEnabledReporterTest() { ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - mFlinger.mutableEventQueue().reset(mMessageQueue); setupScheduler(); mFlinger.setupComposer(std::make_unique()); mFlinger.flinger()->mTunnelModeEnabledReporter = mTunnelModeEnabledReporter; diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp deleted file mode 100644 index 5fb06fd65f..0000000000 --- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2018 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 "mock/MockMessageQueue.h" - -namespace android::mock { - -MessageQueue::MessageQueue() { - ON_CALL(*this, postMessage).WillByDefault([](sp&& handler) { - // Execute task to prevent broken promise exception on destruction. - handler->handleMessage(Message()); - }); -} - -MessageQueue::~MessageQueue() = default; - -} // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h deleted file mode 100644 index d68433760d..0000000000 --- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2018 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 - -#include "FrameTimeline.h" -#include "Scheduler/EventThread.h" -#include "Scheduler/MessageQueue.h" - -namespace android::mock { - -class MessageQueue : public android::MessageQueue { -public: - MessageQueue(); - ~MessageQueue() override; - - MOCK_METHOD1(setInjector, void(sp)); - MOCK_METHOD0(waitMessage, void()); - MOCK_METHOD1(postMessage, void(sp&&)); - MOCK_METHOD3(initVsync, - void(scheduler::VSyncDispatch&, frametimeline::TokenManager&, - std::chrono::nanoseconds)); - MOCK_METHOD1(setDuration, void(std::chrono::nanoseconds workDuration)); - - MOCK_METHOD(void, scheduleCommit, (), (override)); - MOCK_METHOD(void, scheduleComposite, (), (override)); - - MOCK_METHOD(std::optional, getScheduledFrameTime, (), (const, override)); -}; - -} // namespace android::mock -- cgit v1.2.3-59-g8ed1b From 0acd33a338821d3f3e30677f5f5505cae69d527d Mon Sep 17 00:00:00 2001 From: chaviw Date: Tue, 2 Nov 2021 11:55:37 -0500 Subject: Add ability to process buffers into the same syncTransaction In a normal sync case, we send the syncTransaction and then clear it as soon as a buffer is acquired and placed in the transaction. However, in some cases, we want to continue processing buffers into the sync transaction until we get the signal to stop. This is for cases when we don't have a clear signal which buffer wants to be synced, but know when it's done waiting for the correct buffer. This also adds a way to retrieve and clear the buffer from the transaction to allow BBQ to release the buffer when it knows it's ready to acquire a new buffer. This speeds up the process so BBQ doesn't need to wait for the asynchronous callback to release the previous buffer. This new machanism can be used to synchronize SurfaceViews because it knows when something has been changed and to wait until the app has notified that it's drawn. Once it's notified, we can stop processing frames into the sync transaction and allow the transaction to be applied with the main window. Bug: 200284684 Test: BLASTBufferQueueTest Change-Id: Ibdb524270de368033cf8835f0c305e8a5756ff6e --- libs/gui/BLASTBufferQueue.cpp | 96 ++++++++++++++++++---------- libs/gui/SurfaceComposerClient.cpp | 30 +++++++++ libs/gui/include/gui/BLASTBufferQueue.h | 11 +++- libs/gui/include/gui/SurfaceComposerClient.h | 3 + libs/gui/tests/BLASTBufferQueue_test.cpp | 52 +++++++++++++-- 5 files changed, 154 insertions(+), 38 deletions(-) diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index e9149f3a3e..55703214a5 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -407,18 +407,9 @@ void BLASTBufferQueue::releaseBufferCallback( // Release all buffers that are beyond the ones that we need to hold while (mPendingRelease.size() > numPendingBuffersToHold) { - const auto releaseBuffer = mPendingRelease.front(); + const auto releasedBuffer = mPendingRelease.front(); mPendingRelease.pop_front(); - auto it = mSubmitted.find(releaseBuffer.callbackId); - if (it == mSubmitted.end()) { - BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %s", - releaseBuffer.callbackId.to_string().c_str()); - return; - } - mNumAcquired--; - BQA_LOGV("released %s", releaseBuffer.callbackId.to_string().c_str()); - mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence); - mSubmitted.erase(it); + releaseBuffer(releasedBuffer.callbackId, releasedBuffer.releaseFence); // Don't process the transactions here if mWaitForTransactionCallback is set. Instead, let // onFrameAvailable handle processing them since it will merge with the syncTransaction. if (!mWaitForTransactionCallback) { @@ -432,6 +423,20 @@ void BLASTBufferQueue::releaseBufferCallback( mCallbackCV.notify_all(); } +void BLASTBufferQueue::releaseBuffer(const ReleaseCallbackId& callbackId, + const sp& releaseFence) { + auto it = mSubmitted.find(callbackId); + if (it == mSubmitted.end()) { + BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %s", + callbackId.to_string().c_str()); + return; + } + mNumAcquired--; + BQA_LOGV("released %s", callbackId.to_string().c_str()); + mBufferItemConsumer->releaseBuffer(it->second, releaseFence); + mSubmitted.erase(it); +} + void BLASTBufferQueue::acquireNextBufferLocked( const std::optional transaction) { ATRACE_CALL(); @@ -589,34 +594,57 @@ void BLASTBufferQueue::acquireAndReleaseBuffer() { mBufferItemConsumer->releaseBuffer(bufferItem, bufferItem.mFence); } +void BLASTBufferQueue::flushAndWaitForFreeBuffer(std::unique_lock& lock) { + if (mWaitForTransactionCallback && mNumFrameAvailable > 0) { + // We are waiting on a previous sync's transaction callback so allow another sync + // transaction to proceed. + // + // We need to first flush out the transactions that were in between the two syncs. + // We do this by merging them into mSyncTransaction so any buffer merging will get + // a release callback invoked. The release callback will be async so we need to wait + // on max acquired to make sure we have the capacity to acquire another buffer. + if (maxBuffersAcquired(false /* includeExtraAcquire */)) { + BQA_LOGD("waiting to flush shadow queue..."); + mCallbackCV.wait(lock); + } + while (mNumFrameAvailable > 0) { + // flush out the shadow queue + acquireAndReleaseBuffer(); + } + } + + while (maxBuffersAcquired(false /* includeExtraAcquire */)) { + BQA_LOGD("waiting for free buffer."); + mCallbackCV.wait(lock); + } +} + void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { ATRACE_CALL(); std::unique_lock _lock{mMutex}; const bool syncTransactionSet = mSyncTransaction != nullptr; BQA_LOGV("onFrameAvailable-start syncTransactionSet=%s", boolToString(syncTransactionSet)); + if (syncTransactionSet) { - if (mWaitForTransactionCallback) { - // We are waiting on a previous sync's transaction callback so allow another sync - // transaction to proceed. - // - // We need to first flush out the transactions that were in between the two syncs. - // We do this by merging them into mSyncTransaction so any buffer merging will get - // a release callback invoked. The release callback will be async so we need to wait - // on max acquired to make sure we have the capacity to acquire another buffer. - if (maxBuffersAcquired(false /* includeExtraAcquire */)) { - BQA_LOGD("waiting to flush shadow queue..."); - mCallbackCV.wait(_lock); - } - while (mNumFrameAvailable > 0) { - // flush out the shadow queue - acquireAndReleaseBuffer(); + bool mayNeedToWaitForBuffer = true; + // If we are going to re-use the same mSyncTransaction, release the buffer that may already + // be set in the Transaction. This is to allow us a free slot early to continue processing + // a new buffer. + if (!mAcquireSingleBuffer) { + auto bufferData = mSyncTransaction->getAndClearBuffer(mSurfaceControl); + if (bufferData) { + BQA_LOGD("Releasing previous buffer when syncing: framenumber=%" PRIu64, + bufferData->frameNumber); + releaseBuffer(bufferData->releaseCallbackId, bufferData->acquireFence); + // Because we just released a buffer, we know there's no need to wait for a free + // buffer. + mayNeedToWaitForBuffer = false; } } - while (maxBuffersAcquired(false /* includeExtraAcquire */)) { - BQA_LOGD("waiting for free buffer."); - mCallbackCV.wait(_lock); + if (mayNeedToWaitForBuffer) { + flushAndWaitForFreeBuffer(_lock); } } @@ -629,8 +657,10 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { boolToString(syncTransactionSet)); if (syncTransactionSet) { - acquireNextBufferLocked(std::move(mSyncTransaction)); - mSyncTransaction = nullptr; + acquireNextBufferLocked(mSyncTransaction); + if (mAcquireSingleBuffer) { + mSyncTransaction = nullptr; + } mWaitForTransactionCallback = true; } else if (!mWaitForTransactionCallback) { acquireNextBufferLocked(std::nullopt); @@ -652,9 +682,11 @@ void BLASTBufferQueue::onFrameCancelled(const uint64_t bufferId) { mDequeueTimestamps.erase(bufferId); }; -void BLASTBufferQueue::setSyncTransaction(SurfaceComposerClient::Transaction* t) { +void BLASTBufferQueue::setSyncTransaction(SurfaceComposerClient::Transaction* t, + bool acquireSingleBuffer) { std::lock_guard _lock{mMutex}; mSyncTransaction = t; + mAcquireSingleBuffer = mSyncTransaction ? acquireSingleBuffer : true; } bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 2713be060a..b139cf126c 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -413,6 +413,14 @@ ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLock return callback; } +void TransactionCompletedListener::removeReleaseBufferCallback( + const ReleaseCallbackId& callbackId) { + { + std::scoped_lock lock(mMutex); + popReleaseBufferCallbackLocked(callbackId); + } +} + // --------------------------------------------------------------------------- void removeDeadBufferCallback(void* /*context*/, uint64_t graphicBufferId); @@ -1307,6 +1315,28 @@ SurfaceComposerClient::Transaction::setTransformToDisplayInverse(const sp SurfaceComposerClient::Transaction::getAndClearBuffer( + const sp& sc) { + layer_state_t* s = getLayerState(sc); + if (!s) { + return std::nullopt; + } + if (!(s->what & layer_state_t::eBufferChanged)) { + return std::nullopt; + } + + BufferData bufferData = s->bufferData; + + TransactionCompletedListener::getInstance()->removeReleaseBufferCallback( + bufferData.releaseCallbackId); + BufferData emptyBufferData; + s->what &= ~layer_state_t::eBufferChanged; + s->bufferData = emptyBufferData; + + mContainsBuffer = false; + return bufferData; +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer( const sp& sc, const sp& buffer, const std::optional>& fence, const std::optional& frameNumber, diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index f718de8c57..d76617373a 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -94,7 +94,7 @@ public: const std::vector& stats); void releaseBufferCallback(const ReleaseCallbackId& id, const sp& releaseFence, std::optional currentMaxAcquiredBufferCount); - void setSyncTransaction(SurfaceComposerClient::Transaction* t); + void setSyncTransaction(SurfaceComposerClient::Transaction* t, bool acquireSingleBuffer = true); void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber); void applyPendingTransactions(uint64_t frameNumber); @@ -132,6 +132,9 @@ private: void flushShadowQueue() REQUIRES(mMutex); void acquireAndReleaseBuffer() REQUIRES(mMutex); + void releaseBuffer(const ReleaseCallbackId& callbackId, const sp& releaseFence) + REQUIRES(mMutex); + void flushAndWaitForFreeBuffer(std::unique_lock& lock); std::string mName; // Represents the queued buffer count from buffer queue, @@ -239,7 +242,11 @@ private: std::queue> mSurfaceControlsWithPendingCallback GUARDED_BY(mMutex); uint32_t mCurrentMaxAcquiredBufferCount; - bool mWaitForTransactionCallback = false; + bool mWaitForTransactionCallback GUARDED_BY(mMutex) = false; + + // Flag to determine if syncTransaction should only acquire a single buffer and then clear or + // continue to acquire buffers until explicitly cleared + bool mAcquireSingleBuffer GUARDED_BY(mMutex) = true; }; } // namespace android diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index e62c76ed80..e05c3646c6 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -493,6 +493,7 @@ public: const std::optional& frameNumber = std::nullopt, const ReleaseCallbackId& id = ReleaseCallbackId::INVALID_ID, ReleaseBufferCallback callback = nullptr); + std::optional getAndClearBuffer(const sp& sc); Transaction& setDataspace(const sp& sc, ui::Dataspace dataspace); Transaction& setHdrMetadata(const sp& sc, const HdrMetadata& hdrMetadata); Transaction& setSurfaceDamageRegion(const sp& sc, @@ -751,6 +752,8 @@ public: void onReleaseBuffer(ReleaseCallbackId, sp releaseFence, uint32_t currentMaxAcquiredBufferCount) override; + void removeReleaseBufferCallback(const ReleaseCallbackId& callbackId); + // For Testing Only static void setInstance(const sp&); diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 194757fe6b..48b8621be1 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -109,8 +109,8 @@ public: mBlastBufferQueueAdapter->update(sc, width, height, PIXEL_FORMAT_RGBA_8888); } - void setSyncTransaction(Transaction* sync) { - mBlastBufferQueueAdapter->setSyncTransaction(sync); + void setSyncTransaction(Transaction* next, bool acquireSingleBuffer = true) { + mBlastBufferQueueAdapter->setSyncTransaction(next, acquireSingleBuffer); } int getWidth() { return mBlastBufferQueueAdapter->mSize.width; } @@ -143,6 +143,11 @@ public: mBlastBufferQueueAdapter->waitForCallback(frameNumber); } + void validateNumFramesSubmitted(int64_t numFramesSubmitted) { + std::unique_lock lock{mBlastBufferQueueAdapter->mMutex}; + ASSERT_EQ(numFramesSubmitted, mBlastBufferQueueAdapter->mSubmitted.size()); + } + private: sp mBlastBufferQueueAdapter; }; @@ -298,7 +303,7 @@ protected: auto ret = igbp->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight, PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr, nullptr); - ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); + ASSERT_TRUE(ret == IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION || ret == NO_ERROR); ASSERT_EQ(OK, igbp->requestBuffer(slot, &buf)); uint32_t* bufData; @@ -818,7 +823,7 @@ TEST_F(BLASTBufferQueueTest, SyncThenNoSync) { CallbackData callbackData; transactionCallback.getCallbackData(&callbackData); - // capture screen and verify that it is red + // capture screen and verify that it is green ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(0, 255, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); @@ -1025,6 +1030,45 @@ TEST_F(BLASTBufferQueueTest, RunOutOfBuffersWaitingOnSF) { checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); } +TEST_F(BLASTBufferQueueTest, SetSyncTransactionAcquireMultipleBuffers) { + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + + sp igbProducer; + setUpProducer(adapter, igbProducer); + + Transaction next; + adapter.setSyncTransaction(&next, false); + queueBuffer(igbProducer, 0, 255, 0, 0); + queueBuffer(igbProducer, 0, 0, 255, 0); + // There should only be one frame submitted since the first frame will be released. + adapter.validateNumFramesSubmitted(1); + adapter.setSyncTransaction(nullptr); + + // queue non sync buffer, so this one should get blocked + // Add a present delay to allow the first screenshot to get taken. + nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count(); + queueBuffer(igbProducer, 255, 0, 0, presentTimeDelay); + + CallbackHelper transactionCallback; + next.addTransactionCompletedCallback(transactionCallback.function, + transactionCallback.getContext()) + .apply(); + + CallbackData callbackData; + transactionCallback.getCallbackData(&callbackData); + + // capture screen and verify that it is blue + ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(0, 0, 255, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); + + mProducerListener->waitOnNumberReleased(2); + // capture screen and verify that it is red + ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(255, 0, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); +} + class TestProducerListener : public BnProducerListener { public: sp mIgbp; -- cgit v1.2.3-59-g8ed1b From 4b238fb0a9bd5533651030faf22391675fc88024 Mon Sep 17 00:00:00 2001 From: Dmitri Plotnikov Date: Tue, 9 Nov 2021 11:52:08 -0800 Subject: Reset time-since-update if the tracked value is nonmonotonic The absence of this reset led to timeInStateSinceUpdate exceeding total timeSinceUpdate. This resulted in inflated counts, which are smeared using the `delta * timeInState / timeSinceUpdate` formula. So, instead of assigning a portion of the time to a specific state it would assign a multiple of the time to it. Bug: 204087731 Test: atest libbattery_test Change-Id: I7805d5c6aa314f4030c8a1ac9541f2d439a471cb --- libs/battery/MultiStateCounter.h | 8 ++++++++ libs/battery/MultiStateCounterTest.cpp | 23 ++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/libs/battery/MultiStateCounter.h b/libs/battery/MultiStateCounter.h index 03e1f2a022..a2b59a877f 100644 --- a/libs/battery/MultiStateCounter.h +++ b/libs/battery/MultiStateCounter.h @@ -195,10 +195,18 @@ const T& MultiStateCounter::updateValue(const T& value, time_t timestamp) { << ", which is lower than the previous value " << valueToString(lastValue) << "\n"; ALOGE("%s", str.str().c_str()); + + for (int i = 0; i < stateCount; i++) { + states[i].timeInStateSinceUpdate = 0; + } } } else if (timestamp < lastUpdateTimestamp) { ALOGE("updateValue is called with an earlier timestamp: %lu, previous: %lu\n", (unsigned long)timestamp, (unsigned long)lastUpdateTimestamp); + + for (int i = 0; i < stateCount; i++) { + states[i].timeInStateSinceUpdate = 0; + } } } } diff --git a/libs/battery/MultiStateCounterTest.cpp b/libs/battery/MultiStateCounterTest.cpp index 848fd10d15..876bf745a8 100644 --- a/libs/battery/MultiStateCounterTest.cpp +++ b/libs/battery/MultiStateCounterTest.cpp @@ -176,7 +176,7 @@ TEST_F(MultiStateCounterTest, timeAdjustment_updateValue) { testCounter.setState(0, 0); testCounter.updateValue(6.0, 2000); - // Time moves back. The negative delta from 2000 to 1000 is ignored + // Time moves back. The delta over the negative interval from 2000 to 1000 is ignored testCounter.updateValue(8.0, 1000); double delta = testCounter.updateValue(11.0, 3000); @@ -189,6 +189,27 @@ TEST_F(MultiStateCounterTest, timeAdjustment_updateValue) { EXPECT_DOUBLE_EQ(3.0, delta); } +TEST_F(MultiStateCounterTest, updateValue_nonmonotonic) { + DoubleMultiStateCounter testCounter(2, 0); + testCounter.updateValue(0, 0); + testCounter.setState(0, 0); + testCounter.updateValue(6.0, 2000); + + // Value goes down. The negative delta from 6.0 to 4.0 is ignored + testCounter.updateValue(4.0, 3000); + + // Value goes up again. The positive delta from 4.0 to 7.0 is accumulated. + double delta = testCounter.updateValue(7.0, 4000); + + // The total accumulated count is: + // 6.0 // For the period 0-2000 + // +(7.0-4.0) // For the period 3000-4000 + EXPECT_DOUBLE_EQ(9.0, testCounter.getCount(0)); + + // 7.0-4.0 + EXPECT_DOUBLE_EQ(3.0, delta); +} + TEST_F(MultiStateCounterTest, addValue) { DoubleMultiStateCounter testCounter(1, 0); testCounter.updateValue(0, 0); -- cgit v1.2.3-59-g8ed1b From 46f3e3b68fe01e23b1c903ed11b75d0c8efd774d Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Tue, 10 Aug 2021 11:44:24 -0700 Subject: SF: Merge commit/composite in MessageQueue scheduleComposite is unnecessary, as commit and/or composite are dispatched from the same message/task. Bug: 185535769 Test: libsurfaceflinger_unittest Change-Id: I8de8b89d9311049598165a46a30ddbf6a4d0c8d4 --- services/surfaceflinger/Scheduler/MessageQueue.cpp | 51 ++++++++-------------- services/surfaceflinger/Scheduler/MessageQueue.h | 14 ++---- services/surfaceflinger/Scheduler/Scheduler.h | 3 +- services/surfaceflinger/SurfaceFlinger.cpp | 10 ++--- .../tests/unittests/CompositionTest.cpp | 2 +- .../tests/unittests/MessageQueueTest.cpp | 16 +++---- .../tests/unittests/SetFrameRateTest.cpp | 18 ++++---- .../unittests/SurfaceFlinger_CreateDisplayTest.cpp | 4 +- .../SurfaceFlinger_DestroyDisplayTest.cpp | 2 +- .../tests/unittests/SurfaceFlinger_HotplugTest.cpp | 4 +- .../SurfaceFlinger_OnInitializeDisplaysTest.cpp | 2 +- .../SurfaceFlinger_SetPowerModeInternalTest.cpp | 2 +- .../tests/unittests/TestableScheduler.h | 2 +- .../tests/unittests/TransactionApplicationTest.cpp | 10 ++--- 14 files changed, 58 insertions(+), 82 deletions(-) diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp index 043a536216..a020e2c834 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.cpp +++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp @@ -30,41 +30,30 @@ namespace android::impl { -void MessageQueue::Handler::dispatchComposite() { - if ((mEventMask.fetch_or(kComposite) & kComposite) == 0) { - mQueue.mLooper->sendMessage(this, Message(kComposite)); - } -} - -void MessageQueue::Handler::dispatchCommit(int64_t vsyncId, nsecs_t expectedVsyncTime) { - if ((mEventMask.fetch_or(kCommit) & kCommit) == 0) { +void MessageQueue::Handler::dispatchFrame(int64_t vsyncId, nsecs_t expectedVsyncTime) { + if (!mFramePending.exchange(true)) { mVsyncId = vsyncId; mExpectedVsyncTime = expectedVsyncTime; - mQueue.mLooper->sendMessage(this, Message(kCommit)); + mQueue.mLooper->sendMessage(this, Message()); } } bool MessageQueue::Handler::isFramePending() const { - constexpr auto kPendingMask = kCommit | kComposite; - return (mEventMask.load() & kPendingMask) != 0; + return mFramePending.load(); } -void MessageQueue::Handler::handleMessage(const Message& message) { +void MessageQueue::Handler::handleMessage(const Message&) { + mFramePending.store(false); + const nsecs_t frameTime = systemTime(); - switch (message.what) { - case kCommit: - mEventMask.fetch_and(~kCommit); - if (!mQueue.mCompositor.commit(frameTime, mVsyncId, mExpectedVsyncTime)) { - return; - } - // Composite immediately, rather than after pending tasks through scheduleComposite. - [[fallthrough]]; - case kComposite: - mEventMask.fetch_and(~kComposite); - mQueue.mCompositor.composite(frameTime); - mQueue.mCompositor.sample(); - break; + auto& compositor = mQueue.mCompositor; + + if (!compositor.commit(frameTime, mVsyncId, mExpectedVsyncTime)) { + return; } + + compositor.composite(frameTime); + compositor.sample(); } MessageQueue::MessageQueue(ICompositor& compositor) @@ -122,7 +111,7 @@ void MessageQueue::vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, ns const auto vsyncId = mVsync.tokenManager->generateTokenForPredictions( {targetWakeupTime, readyTime, vsyncTime}); - mHandler->dispatchCommit(vsyncId, vsyncTime); + mHandler->dispatchFrame(vsyncId, vsyncTime); } void MessageQueue::initVsync(scheduler::VSyncDispatch& dispatch, @@ -176,7 +165,7 @@ void MessageQueue::postMessage(sp&& handler) { mLooper->sendMessage(handler, Message()); } -void MessageQueue::scheduleCommit() { +void MessageQueue::scheduleFrame() { ATRACE_CALL(); { @@ -195,18 +184,14 @@ void MessageQueue::scheduleCommit() { .earliestVsync = mVsync.lastCallbackTime.count()}); } -void MessageQueue::scheduleComposite() { - mHandler->dispatchComposite(); -} - void MessageQueue::injectorCallback() { ssize_t n; DisplayEventReceiver::Event buffer[8]; while ((n = DisplayEventReceiver::getEvents(&mInjector.tube, buffer, 8)) > 0) { for (int i = 0; i < n; i++) { if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { - mHandler->dispatchCommit(buffer[i].vsync.vsyncId, - buffer[i].vsync.expectedVSyncTimestamp); + auto& vsync = buffer[i].vsync; + mHandler->dispatchFrame(vsync.vsyncId, vsync.expectedVSyncTimestamp); break; } } diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h index 2c908a6983..dd69d60580 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.h +++ b/services/surfaceflinger/Scheduler/MessageQueue.h @@ -71,8 +71,7 @@ public: virtual void setInjector(sp) = 0; virtual void waitMessage() = 0; virtual void postMessage(sp&&) = 0; - virtual void scheduleCommit() = 0; - virtual void scheduleComposite() = 0; + virtual void scheduleFrame() = 0; using Clock = std::chrono::steady_clock; virtual std::optional getScheduledFrameTime() const = 0; @@ -83,11 +82,8 @@ namespace impl { class MessageQueue : public android::MessageQueue { protected: class Handler : public MessageHandler { - static constexpr uint32_t kCommit = 0b1; - static constexpr uint32_t kComposite = 0b10; - MessageQueue& mQueue; - std::atomic mEventMask = 0; + std::atomic_bool mFramePending = false; std::atomic mVsyncId = 0; std::atomic mExpectedVsyncTime = 0; @@ -97,8 +93,7 @@ protected: bool isFramePending() const; - virtual void dispatchCommit(int64_t vsyncId, nsecs_t expectedVsyncTime); - void dispatchComposite(); + virtual void dispatchFrame(int64_t vsyncId, nsecs_t expectedVsyncTime); }; friend class Handler; @@ -147,8 +142,7 @@ public: void waitMessage() override; void postMessage(sp&&) override; - void scheduleCommit() override; - void scheduleComposite() override; + void scheduleFrame() override; std::optional getScheduledFrameTime() const override; }; diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 6d45b5d69b..f3c5b353e0 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -97,8 +97,7 @@ public: using Impl::getScheduledFrameTime; using Impl::setDuration; - using Impl::scheduleCommit; - using Impl::scheduleComposite; + using Impl::scheduleFrame; // Schedule an asynchronous or synchronous task on the main thread. template > diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 93f8406319..4c90a04dab 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1702,7 +1702,7 @@ void SurfaceFlinger::scheduleCommit(FrameHint hint) { mScheduler->resetIdleTimer(); } mPowerAdvisor.notifyDisplayUpdateImminent(); - mScheduler->scheduleCommit(); + mScheduler->scheduleFrame(); } void SurfaceFlinger::scheduleComposite(FrameHint hint) { @@ -1928,7 +1928,7 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected // fired yet just wait for the next commit. if (mSetActiveModePending) { if (framePending) { - mScheduler->scheduleCommit(); + mScheduler->scheduleFrame(); return false; } @@ -5324,6 +5324,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r scheduleRepaint(); return NO_ERROR; case 1004: // Force composite ahead of next VSYNC. + case 1006: scheduleComposite(FrameHint::kActive); return NO_ERROR; case 1005: { // Force commit ahead of next VSYNC. @@ -5332,9 +5333,6 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r eTraversalNeeded); return NO_ERROR; } - case 1006: // Force composite immediately. - mScheduler->scheduleComposite(); - return NO_ERROR; case 1007: // Unused. return NAME_NOT_FOUND; case 1008: // Toggle forced GPU composition. @@ -5752,7 +5750,7 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { const bool timerExpired = mKernelIdleTimerEnabled && expired; if (display->onKernelTimerChanged(desiredModeId, timerExpired)) { - mScheduler->scheduleCommit(); + mScheduler->scheduleFrame(); } })); } diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 0c9e6e1ed3..8d2c078305 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -536,7 +536,7 @@ struct BaseLayerProperties { ASSERT_EQ(NO_ERROR, err); Mock::VerifyAndClear(test->mRenderEngine); - EXPECT_CALL(*test->mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*test->mFlinger.scheduler(), scheduleFrame()).Times(1); enqueueBuffer(test, layer); Mock::VerifyAndClearExpectations(test->mFlinger.scheduler()); diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp index 17d1dd6b09..bd4dc593ba 100644 --- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp @@ -41,7 +41,7 @@ class TestableMessageQueue : public impl::MessageQueue { struct MockHandler : MessageQueue::Handler { using MessageQueue::Handler::Handler; - MOCK_METHOD(void, dispatchCommit, (int64_t, nsecs_t), (override)); + MOCK_METHOD(void, dispatchFrame, (int64_t, nsecs_t), (override)); }; explicit TestableMessageQueue(sp handler) @@ -96,7 +96,7 @@ TEST_F(MessageQueueTest, commit) { EXPECT_FALSE(mEventQueue.getScheduledFrameTime()); EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234)); - EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit()); + EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame()); ASSERT_TRUE(mEventQueue.getScheduledFrameTime()); EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count()); @@ -109,13 +109,13 @@ TEST_F(MessageQueueTest, commitTwice) { .earliestVsync = 0}; EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234)); - EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit()); + EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame()); ASSERT_TRUE(mEventQueue.getScheduledFrameTime()); EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count()); EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(4567)); - EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit()); + EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame()); ASSERT_TRUE(mEventQueue.getScheduledFrameTime()); EXPECT_EQ(4567, mEventQueue.getScheduledFrameTime()->time_since_epoch().count()); @@ -128,7 +128,7 @@ TEST_F(MessageQueueTest, commitTwiceWithCallback) { .earliestVsync = 0}; EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234)); - EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit()); + EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame()); ASSERT_TRUE(mEventQueue.getScheduledFrameTime()); EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count()); @@ -141,7 +141,7 @@ TEST_F(MessageQueueTest, commitTwiceWithCallback) { generateTokenForPredictions( frametimeline::TimelineItem(startTime, endTime, presentTime))) .WillOnce(Return(vsyncId)); - EXPECT_CALL(*mEventQueue.mHandler, dispatchCommit(vsyncId, presentTime)).Times(1); + EXPECT_CALL(*mEventQueue.mHandler, dispatchFrame(vsyncId, presentTime)).Times(1); EXPECT_NO_FATAL_FAILURE(mEventQueue.vsyncCallback(presentTime, startTime, endTime)); EXPECT_FALSE(mEventQueue.getScheduledFrameTime()); @@ -152,7 +152,7 @@ TEST_F(MessageQueueTest, commitTwiceWithCallback) { .earliestVsync = presentTime}; EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timingAfterCallback)).WillOnce(Return(0)); - EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit()); + EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame()); } TEST_F(MessageQueueTest, commitWithDurationChange) { @@ -164,7 +164,7 @@ TEST_F(MessageQueueTest, commitWithDurationChange) { .earliestVsync = 0}; EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(0)); - EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit()); + EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame()); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index 115a44db4a..eed62a70c3 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -169,7 +169,7 @@ void SetFrameRateTest::setupScheduler() { namespace { TEST_P(SetFrameRateTest, SetAndGet) { - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); const auto& layerFactory = GetParam(); @@ -180,7 +180,7 @@ TEST_P(SetFrameRateTest, SetAndGet) { } TEST_P(SetFrameRateTest, SetAndGetParent) { - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); const auto& layerFactory = GetParam(); @@ -205,7 +205,7 @@ TEST_P(SetFrameRateTest, SetAndGetParent) { } TEST_P(SetFrameRateTest, SetAndGetParentAllVote) { - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); const auto& layerFactory = GetParam(); @@ -244,7 +244,7 @@ TEST_P(SetFrameRateTest, SetAndGetParentAllVote) { } TEST_P(SetFrameRateTest, SetAndGetChild) { - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); const auto& layerFactory = GetParam(); @@ -269,7 +269,7 @@ TEST_P(SetFrameRateTest, SetAndGetChild) { } TEST_P(SetFrameRateTest, SetAndGetChildAllVote) { - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); const auto& layerFactory = GetParam(); @@ -308,7 +308,7 @@ TEST_P(SetFrameRateTest, SetAndGetChildAllVote) { } TEST_P(SetFrameRateTest, SetAndGetChildAddAfterVote) { - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); const auto& layerFactory = GetParam(); @@ -338,7 +338,7 @@ TEST_P(SetFrameRateTest, SetAndGetChildAddAfterVote) { } TEST_P(SetFrameRateTest, SetAndGetChildRemoveAfterVote) { - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); const auto& layerFactory = GetParam(); @@ -369,7 +369,7 @@ TEST_P(SetFrameRateTest, SetAndGetChildRemoveAfterVote) { } TEST_P(SetFrameRateTest, SetAndGetParentNotInTree) { - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); const auto& layerFactory = GetParam(); @@ -464,7 +464,7 @@ TEST_P(SetFrameRateTest, SetOnParentActivatesTree) { } TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) { - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); const auto& layerFactory = GetParam(); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp index 2236db7ab3..f7d34ac5da 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp @@ -52,7 +52,7 @@ TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForNonsecureDisplay) { // Cleanup conditions // Creating the display commits a display transaction. - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); } TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForSecureDisplay) { @@ -87,7 +87,7 @@ TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForSecureDisplay) { // Cleanup conditions // Creating the display commits a display transaction. - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp index bcd3222f8a..c7e61c96d6 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp @@ -41,7 +41,7 @@ TEST_F(DestroyDisplayTest, destroyDisplayClearsCurrentStateForDisplay) { EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1); // Destroying the display commits a display transaction. - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); // -------------------------------------------------------------------- // Invocation diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp index cc979c91c7..c9a2b00fa3 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp @@ -39,7 +39,7 @@ TEST_F(HotplugTest, enqueuesEventsForDisplayTransaction) { // Call Expectations // We expect a scheduled commit for the display transaction. - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); // -------------------------------------------------------------------- // Invocation @@ -86,7 +86,7 @@ TEST_F(HotplugTest, processesEnqueuedEventsIfCalledOnMainThread) { // Call Expectations // We expect a scheduled commit for the display transaction. - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); // -------------------------------------------------------------------- // Invocation diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp index 83b150f93f..37cf05ef64 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp @@ -47,7 +47,7 @@ TEST_F(OnInitializeDisplaysTest, onInitializeDisplaysSetsUpPrimaryDisplay) { Case::Display::setupHwcGetActiveConfigCallExpectations(this); // We expect a scheduled commit for the display transaction. - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp index ad696aab43..b57feffe83 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp @@ -273,7 +273,7 @@ struct DisplayPowerCase { } static void setupRepaintEverythingCallExpectations(DisplayTransactionTest* test) { - EXPECT_CALL(*test->mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*test->mFlinger.scheduler(), scheduleFrame()).Times(1); } static void setupSurfaceInterceptorCallExpectations(DisplayTransactionTest* test, diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 32ec84853b..9d1fc981aa 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -52,7 +52,7 @@ public: }); } - MOCK_METHOD(void, scheduleCommit, (), (override)); + MOCK_METHOD(void, scheduleFrame, (), (override)); MOCK_METHOD(void, postMessage, (sp&&), (override)); // Used to inject mock event thread. diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index b3a6a1b264..ec19100c2b 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -143,7 +143,7 @@ public: void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) { ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); TransactionInfo transaction; setupSingle(transaction, flags, syncInputWindows, /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, @@ -173,7 +173,7 @@ public: void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) { ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); // first check will see desired present time has not passed, // but afterwards it will look like the desired present time has passed @@ -204,9 +204,9 @@ public: ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); nsecs_t time = systemTime(); if (!syncInputWindows) { - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(2); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(2); } else { - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); } // transaction that should go on the pending thread TransactionInfo transactionA; @@ -451,7 +451,7 @@ public: TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); - EXPECT_CALL(*mFlinger.scheduler(), scheduleCommit()).Times(1); + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); TransactionInfo transactionA; // transaction to go on pending queue setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false, -- cgit v1.2.3-59-g8ed1b From 68dee2bc1c6155e4e6cea8e460551b8ce44856fa Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 8 Nov 2021 18:52:12 -0800 Subject: SF: Add LayerCreationArgs to transaction proto Add LayerCreationArgs to transaction proto so we have the relevant info to recreate layers from transaction traces. Test: presubmit Bug: 200284593 Change-Id: I2721052a3ac38fd4cd33939a4d53c72647454edc --- .../Tracing/TransactionProtoParser.cpp | 200 ++++++++++++++------- .../Tracing/TransactionProtoParser.h | 53 ++++-- .../surfaceflinger/layerproto/transactions.proto | 119 ++++++------ .../tests/unittests/TransactionProtoParserTest.cpp | 8 +- 4 files changed, 244 insertions(+), 136 deletions(-) diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp index fb1d43bf6c..d1dc07639a 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp @@ -22,9 +22,9 @@ namespace android::surfaceflinger { -proto::TransactionState TransactionProtoParser::toProto( - const TransactionState& t, std::function&)> getLayerId, - std::function&)> getDisplayId) { +proto::TransactionState TransactionProtoParser::toProto(const TransactionState& t, + LayerHandleToIdFn getLayerId, + DisplayHandleToIdFn getDisplayId) { proto::TransactionState proto; proto.set_pid(t.originPid); proto.set_uid(t.originUid); @@ -42,10 +42,38 @@ proto::TransactionState TransactionProtoParser::toProto( return proto; } -proto::LayerState TransactionProtoParser::toProto( - const layer_state_t& layer, std::function&)> getLayerId) { +proto::TransactionState TransactionProtoParser::toProto( + std::vector> states) { + proto::TransactionState proto; + for (auto& [layerId, state] : states) { + proto::LayerState layerProto = toProto(state, nullptr); + if (layerProto.has_buffer_data()) { + proto::LayerState_BufferData* bufferProto = layerProto.mutable_buffer_data(); + bufferProto->set_buffer_id(state.bufferId); + bufferProto->set_width(state.bufferWidth); + bufferProto->set_height(state.bufferHeight); + } + layerProto.set_has_sideband_stream(state.hasSidebandStream); + layerProto.set_layer_id(state.layerId); + layerProto.set_parent_id(state.parentId); + layerProto.set_relative_parent_id(state.relativeParentId); + if (layerProto.has_window_info_handle()) { + layerProto.mutable_window_info_handle()->set_crop_layer_id(state.inputCropId); + } + proto.mutable_layer_changes()->Add(std::move(layerProto)); + } + return proto; +} + +proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer, + LayerHandleToIdFn getLayerId) { proto::LayerState proto; - proto.set_layer_id(layer.layerId); + if (getLayerId != nullptr) { + proto.set_layer_id(getLayerId(layer.surface)); + } else { + proto.set_layer_id(layer.layerId); + } + proto.set_what(layer.what); if (layer.what & layer_state_t::ePositionChanged) { @@ -130,13 +158,13 @@ proto::LayerState TransactionProtoParser::toProto( } } - if (layer.what & layer_state_t::eReparent) { + if ((layer.what & layer_state_t::eReparent) && getLayerId != nullptr) { int32_t layerId = layer.parentSurfaceControlForChild ? getLayerId(layer.parentSurfaceControlForChild->getHandle()) : -1; proto.set_parent_id(layerId); } - if (layer.what & layer_state_t::eRelativeLayerChanged) { + if ((layer.what & layer_state_t::eRelativeLayerChanged) && getLayerId != nullptr) { int32_t layerId = layer.relativeLayerSurfaceControl ? getLayerId(layer.relativeLayerSurfaceControl->getHandle()) : -1; @@ -164,8 +192,12 @@ proto::LayerState TransactionProtoParser::toProto( transformProto->set_ty(inputInfo->transform.ty()); windowInfoProto->set_replace_touchable_region_with_crop( inputInfo->replaceTouchableRegionWithCrop); - windowInfoProto->set_crop_layer_id( - getLayerId(inputInfo->touchableRegionCropHandle.promote())); + if (getLayerId != nullptr) { + windowInfoProto->set_crop_layer_id( + getLayerId(inputInfo->touchableRegionCropHandle.promote())); + } else { + windowInfoProto->set_crop_layer_id(-1); + } } } if (layer.what & layer_state_t::eBackgroundColorChanged) { @@ -212,11 +244,13 @@ proto::LayerState TransactionProtoParser::toProto( return proto; } -proto::DisplayState TransactionProtoParser::toProto( - const DisplayState& display, std::function&)> getDisplayId) { +proto::DisplayState TransactionProtoParser::toProto(const DisplayState& display, + DisplayHandleToIdFn getDisplayId) { proto::DisplayState proto; proto.set_what(display.what); - proto.set_id(getDisplayId(display.token)); + if (getDisplayId != nullptr) { + proto.set_id(getDisplayId(display.token)); + } if (display.what & DisplayState::eLayerStackChanged) { proto.set_layer_stack(display.layerStack.id); @@ -238,9 +272,18 @@ proto::DisplayState TransactionProtoParser::toProto( return proto; } -TransactionState TransactionProtoParser::fromProto( - const proto::TransactionState& proto, std::function(int32_t)> getLayerHandle, - std::function(int32_t)> getDisplayHandle) { +proto::LayerCreationArgs TransactionProtoParser::toProto(const TracingLayerCreationArgs& args) { + proto::LayerCreationArgs proto; + proto.set_layer_id(args.layerId); + proto.set_name(args.name); + proto.set_flags(args.flags); + proto.set_parent_id(args.parentId); + return proto; +} + +TransactionState TransactionProtoParser::fromProto(const proto::TransactionState& proto, + LayerIdToHandleFn getLayerHandle, + DisplayIdToHandleFn getDisplayHandle) { TransactionState t; t.originPid = proto.pid(); t.originUid = proto.uid(); @@ -251,7 +294,7 @@ TransactionState TransactionProtoParser::fromProto( t.states.reserve(static_cast(layerCount)); for (int i = 0; i < layerCount; i++) { ComposerState s; - s.state = std::move(fromProto(proto.layer_changes(i), getLayerHandle)); + fromProto(proto.layer_changes(i), getLayerHandle, s.state); t.states.add(s); } @@ -263,88 +306,116 @@ TransactionState TransactionProtoParser::fromProto( return t; } -layer_state_t TransactionProtoParser::fromProto( - const proto::LayerState& proto, std::function(int32_t)> getLayerHandle) { - layer_state_t layer; +void TransactionProtoParser::fromProto(const proto::LayerCreationArgs& proto, + TracingLayerCreationArgs& outArgs) { + outArgs.layerId = proto.layer_id(); + outArgs.name = proto.name(); + outArgs.flags = proto.flags(); + outArgs.parentId = proto.parent_id(); +} + +void TransactionProtoParser::fromProto(const proto::LayerState& proto, + LayerIdToHandleFn getLayerHandle, + TracingLayerState& outState) { + fromProto(proto, getLayerHandle, static_cast(outState)); + if (proto.what() & layer_state_t::eReparent) { + outState.parentId = proto.parent_id(); + } + if (proto.what() & layer_state_t::eRelativeLayerChanged) { + outState.relativeParentId = proto.relative_parent_id(); + } + if (proto.what() & layer_state_t::eInputInfoChanged) { + outState.inputCropId = proto.window_info_handle().crop_layer_id(); + } + if (proto.what() & layer_state_t::eBufferChanged) { + const proto::LayerState_BufferData& bufferProto = proto.buffer_data(); + outState.bufferId = bufferProto.buffer_id(); + outState.bufferWidth = bufferProto.width(); + outState.bufferHeight = bufferProto.height(); + } + if (proto.what() & layer_state_t::eSidebandStreamChanged) { + outState.hasSidebandStream = proto.has_sideband_stream(); + } +} + +void TransactionProtoParser::fromProto(const proto::LayerState& proto, + LayerIdToHandleFn getLayerHandle, layer_state_t& layer) { layer.layerId = proto.layer_id(); - layer.what = proto.what(); + layer.what |= proto.what(); - if (layer.what & layer_state_t::ePositionChanged) { + if (getLayerHandle != nullptr) { + layer.surface = getLayerHandle(layer.layerId); + } + + if (proto.what() & layer_state_t::ePositionChanged) { layer.x = proto.x(); layer.y = proto.y(); } - if (layer.what & layer_state_t::eLayerChanged) { + if (proto.what() & layer_state_t::eLayerChanged) { layer.z = proto.z(); } - if (layer.what & layer_state_t::eSizeChanged) { + if (proto.what() & layer_state_t::eSizeChanged) { layer.w = proto.w(); layer.h = proto.h(); } - if (layer.what & layer_state_t::eLayerStackChanged) { + if (proto.what() & layer_state_t::eLayerStackChanged) { layer.layerStack.id = proto.layer_stack(); } - if (layer.what & layer_state_t::eFlagsChanged) { + if (proto.what() & layer_state_t::eFlagsChanged) { layer.flags = proto.flags(); layer.mask = proto.mask(); } - if (layer.what & layer_state_t::eMatrixChanged) { + if (proto.what() & layer_state_t::eMatrixChanged) { const proto::LayerState_Matrix22& matrixProto = proto.matrix(); layer.matrix.dsdx = matrixProto.dsdx(); layer.matrix.dsdy = matrixProto.dsdy(); layer.matrix.dtdx = matrixProto.dtdx(); layer.matrix.dtdy = matrixProto.dtdy(); } - if (layer.what & layer_state_t::eCornerRadiusChanged) { + if (proto.what() & layer_state_t::eCornerRadiusChanged) { layer.cornerRadius = proto.corner_radius(); } - if (layer.what & layer_state_t::eBackgroundBlurRadiusChanged) { + if (proto.what() & layer_state_t::eBackgroundBlurRadiusChanged) { layer.backgroundBlurRadius = proto.background_blur_radius(); } - if (layer.what & layer_state_t::eAlphaChanged) { + if (proto.what() & layer_state_t::eAlphaChanged) { layer.alpha = proto.alpha(); } - if (layer.what & layer_state_t::eColorChanged) { + if (proto.what() & layer_state_t::eColorChanged) { const proto::LayerState_Color3& colorProto = proto.color(); layer.color.r = colorProto.r(); layer.color.g = colorProto.g(); layer.color.b = colorProto.b(); } - if (layer.what & layer_state_t::eTransparentRegionChanged) { + if (proto.what() & layer_state_t::eTransparentRegionChanged) { LayerProtoHelper::readFromProto(proto.transparent_region(), layer.transparentRegion); } - if (layer.what & layer_state_t::eTransformChanged) { + if (proto.what() & layer_state_t::eTransformChanged) { layer.transform = proto.transform(); } - if (layer.what & layer_state_t::eTransformToDisplayInverseChanged) { + if (proto.what() & layer_state_t::eTransformToDisplayInverseChanged) { layer.transformToDisplayInverse = proto.transform_to_display_inverse(); } - if (layer.what & layer_state_t::eCropChanged) { + if (proto.what() & layer_state_t::eCropChanged) { LayerProtoHelper::readFromProto(proto.crop(), layer.crop); } - if (layer.what & layer_state_t::eBufferChanged) { + if (proto.what() & layer_state_t::eBufferChanged) { const proto::LayerState_BufferData& bufferProto = proto.buffer_data(); - layer.bufferData.buffer = new GraphicBuffer(bufferProto.width(), bufferProto.height(), - HAL_PIXEL_FORMAT_RGBA_8888, 1, 0); layer.bufferData.frameNumber = bufferProto.frame_number(); layer.bufferData.flags = Flags(bufferProto.flags()); layer.bufferData.cachedBuffer.id = bufferProto.cached_buffer_id(); } - if (layer.what & layer_state_t::eSidebandStreamChanged) { - native_handle_t* handle = native_handle_create(0, 0); - layer.sidebandStream = - proto.has_sideband_stream() ? NativeHandle::create(handle, true) : nullptr; - } - if (layer.what & layer_state_t::eApiChanged) { + if (proto.what() & layer_state_t::eApiChanged) { layer.api = proto.api(); } - if (layer.what & layer_state_t::eColorTransformChanged) { + if (proto.what() & layer_state_t::eColorTransformChanged) { LayerProtoHelper::readFromProto(proto.color_transform(), layer.colorTransform); } - if (layer.what & layer_state_t::eBlurRegionsChanged) { + if (proto.what() & layer_state_t::eBlurRegionsChanged) { layer.blurRegions.reserve(static_cast(proto.blur_regions_size())); for (int i = 0; i < proto.blur_regions_size(); i++) { android::BlurRegion region; @@ -353,20 +424,20 @@ layer_state_t TransactionProtoParser::fromProto( } } - if (layer.what & layer_state_t::eReparent) { + if ((proto.what() & layer_state_t::eReparent) && (getLayerHandle != nullptr)) { int32_t layerId = proto.parent_id(); layer.parentSurfaceControlForChild = new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId), nullptr, layerId); } - if (layer.what & layer_state_t::eRelativeLayerChanged) { + if ((proto.what() & layer_state_t::eRelativeLayerChanged) && (getLayerHandle != nullptr)) { int32_t layerId = proto.relative_parent_id(); layer.relativeLayerSurfaceControl = new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId), nullptr, layerId); } - if ((layer.what & layer_state_t::eInputInfoChanged) && proto.has_window_info_handle()) { + if ((proto.what() & layer_state_t::eInputInfoChanged) && proto.has_window_info_handle()) { gui::WindowInfo inputInfo; const proto::LayerState_WindowInfo& windowInfoProto = proto.window_info_handle(); @@ -385,10 +456,12 @@ layer_state_t TransactionProtoParser::fromProto( inputInfo.replaceTouchableRegionWithCrop = windowInfoProto.replace_touchable_region_with_crop(); int32_t layerId = windowInfoProto.crop_layer_id(); - inputInfo.touchableRegionCropHandle = getLayerHandle(layerId); + if (getLayerHandle != nullptr) { + inputInfo.touchableRegionCropHandle = getLayerHandle(layerId); + } layer.windowInfoHandle = sp::make(inputInfo); } - if (layer.what & layer_state_t::eBackgroundColorChanged) { + if (proto.what() & layer_state_t::eBackgroundColorChanged) { layer.bgColorAlpha = proto.bg_color_alpha(); layer.bgColorDataspace = static_cast(proto.bg_color_dataspace()); const proto::LayerState_Color3& colorProto = proto.color(); @@ -396,44 +469,43 @@ layer_state_t TransactionProtoParser::fromProto( layer.color.g = colorProto.g(); layer.color.b = colorProto.b(); } - if (layer.what & layer_state_t::eColorSpaceAgnosticChanged) { + if (proto.what() & layer_state_t::eColorSpaceAgnosticChanged) { layer.colorSpaceAgnostic = proto.color_space_agnostic(); } - if (layer.what & layer_state_t::eShadowRadiusChanged) { + if (proto.what() & layer_state_t::eShadowRadiusChanged) { layer.shadowRadius = proto.shadow_radius(); } - if (layer.what & layer_state_t::eFrameRateSelectionPriority) { + if (proto.what() & layer_state_t::eFrameRateSelectionPriority) { layer.frameRateSelectionPriority = proto.frame_rate_selection_priority(); } - if (layer.what & layer_state_t::eFrameRateChanged) { + if (proto.what() & layer_state_t::eFrameRateChanged) { layer.frameRate = proto.frame_rate(); layer.frameRateCompatibility = static_cast(proto.frame_rate_compatibility()); layer.changeFrameRateStrategy = static_cast(proto.change_frame_rate_strategy()); } - if (layer.what & layer_state_t::eFixedTransformHintChanged) { + if (proto.what() & layer_state_t::eFixedTransformHintChanged) { layer.fixedTransformHint = static_cast(proto.fixed_transform_hint()); } - if (layer.what & layer_state_t::eAutoRefreshChanged) { + if (proto.what() & layer_state_t::eAutoRefreshChanged) { layer.autoRefresh = proto.auto_refresh(); } - if (layer.what & layer_state_t::eTrustedOverlayChanged) { + if (proto.what() & layer_state_t::eTrustedOverlayChanged) { layer.isTrustedOverlay = proto.is_trusted_overlay(); } - if (layer.what & layer_state_t::eBufferCropChanged) { + if (proto.what() & layer_state_t::eBufferCropChanged) { LayerProtoHelper::readFromProto(proto.buffer_crop(), layer.bufferCrop); } - if (layer.what & layer_state_t::eDestinationFrameChanged) { + if (proto.what() & layer_state_t::eDestinationFrameChanged) { LayerProtoHelper::readFromProto(proto.destination_frame(), layer.destinationFrame); } - if (layer.what & layer_state_t::eDropInputModeChanged) { + if (proto.what() & layer_state_t::eDropInputModeChanged) { layer.dropInputMode = static_cast(proto.drop_input_mode()); } - return layer; } -DisplayState TransactionProtoParser::fromProto( - const proto::DisplayState& proto, std::function(int32_t)> getDisplayHandle) { +DisplayState TransactionProtoParser::fromProto(const proto::DisplayState& proto, + DisplayIdToHandleFn getDisplayHandle) { DisplayState display; display.what = proto.what(); display.token = getDisplayHandle(proto.id()); diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h index a2b8889eb7..e8a139fb98 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.h +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h @@ -21,24 +21,53 @@ #include "TransactionState.h" namespace android::surfaceflinger { + +struct TracingLayerCreationArgs { + int32_t layerId; + std::string name; + uint32_t flags; + int32_t parentId; +}; + +struct TracingLayerState : layer_state_t { + uint64_t bufferId; + uint32_t bufferHeight; + uint32_t bufferWidth; + bool hasSidebandStream; + int32_t parentId; + int32_t relativeParentId; + int32_t inputCropId; + std::string name; + uint32_t layerCreationFlags; +}; + class TransactionProtoParser { public: + typedef std::function(int32_t)> LayerIdToHandleFn; + typedef std::function(int32_t)> DisplayIdToHandleFn; + typedef std::function&)> LayerHandleToIdFn; + typedef std::function&)> DisplayHandleToIdFn; + + static proto::TransactionState toProto(const TransactionState&, LayerHandleToIdFn getLayerIdFn, + DisplayHandleToIdFn getDisplayIdFn); static proto::TransactionState toProto( - const TransactionState&, std::function&)> getLayerIdFn, - std::function&)> getDisplayIdFn); + std::vector>); + + static proto::LayerCreationArgs toProto(const TracingLayerCreationArgs& args); + static TransactionState fromProto(const proto::TransactionState&, - std::function(int32_t)> getLayerHandleFn, - std::function(int32_t)> getDisplayHandleFn); + LayerIdToHandleFn getLayerHandleFn, + DisplayIdToHandleFn getDisplayHandleFn); + static void fromProto(const proto::LayerState&, LayerIdToHandleFn getLayerHandleFn, + TracingLayerState& outState); + static void fromProto(const proto::LayerCreationArgs&, TracingLayerCreationArgs& outArgs); private: - static proto::LayerState toProto(const layer_state_t&, - std::function&)> getLayerId); - static proto::DisplayState toProto(const DisplayState&, - std::function&)> getDisplayId); - static layer_state_t fromProto(const proto::LayerState&, - std::function(int32_t)> getLayerHandle); - static DisplayState fromProto(const proto::DisplayState&, - std::function(int32_t)> getDisplayHandle); + static proto::LayerState toProto(const layer_state_t&, LayerHandleToIdFn getLayerId); + static proto::DisplayState toProto(const DisplayState&, DisplayHandleToIdFn getDisplayId); + static void fromProto(const proto::LayerState&, LayerIdToHandleFn getLayerHandle, + layer_state_t& out); + static DisplayState fromProto(const proto::DisplayState&, DisplayIdToHandleFn getDisplayHandle); }; } // namespace android::surfaceflinger \ No newline at end of file diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto index e7fb1806be..edeacfa72a 100644 --- a/services/surfaceflinger/layerproto/transactions.proto +++ b/services/surfaceflinger/layerproto/transactions.proto @@ -39,21 +39,28 @@ message TransactionTraceFile { } message TransactionTraceEntry { - int64 elapsed_time = 1; + int64 elapsed_realtime_nanos = 1; int64 vsync_id = 2; repeated TransactionState transactions = 3; + repeated LayerCreationArgs new_layers = 4; + repeated DisplayState new_displays = 5; +} + +message LayerCreationArgs { + int32 layer_id = 1; + string name = 2; + uint32 flags = 3; + int32 parent_id = 4; } message TransactionState { - string tag = 2; - int32 pid = 3; - int32 uid = 4; - int64 vsync_id = 5; - int32 input_event_id = 6; - int64 post_time = 7; - repeated LayerState layer_changes = 9; - repeated DisplayState new_displays = 10; - repeated DisplayState display_changes = 11; + int32 pid = 1; + int32 uid = 2; + int64 vsync_id = 3; + int32 input_event_id = 4; + int64 post_time = 5; + repeated LayerState layer_changes = 6; + repeated DisplayState display_changes = 7; } // Keep insync with layer_state_t @@ -130,8 +137,8 @@ message LayerState { eLayerSecure = 0x80; eEnableBackpressure = 0x100; }; - uint32 flags = 10; - uint32 mask = 11; + uint32 flags = 9; + uint32 mask = 10; message Matrix22 { float dsdx = 1; @@ -139,29 +146,29 @@ message LayerState { float dtdy = 3; float dsdy = 4; }; - Matrix22 matrix = 12; - float corner_radius = 13; - uint32 background_blur_radius = 14; - int32 parent_id = 15; - int32 relative_parent_id = 16; + Matrix22 matrix = 11; + float corner_radius = 12; + uint32 background_blur_radius = 13; + int32 parent_id = 14; + int32 relative_parent_id = 15; - float alpha = 50; + float alpha = 16; message Color3 { float r = 1; float g = 2; float b = 3; } - Color3 color = 18; - RegionProto transparent_region = 19; - uint32 transform = 20; - bool transform_to_display_inverse = 21; - RectProto crop = 49; + Color3 color = 17; + RegionProto transparent_region = 18; + uint32 transform = 19; + bool transform_to_display_inverse = 20; + RectProto crop = 21; message BufferData { uint64 buffer_id = 1; uint32 width = 2; uint32 height = 3; - uint64 frame_number = 5; + uint64 frame_number = 4; enum BufferDataChange { BufferDataChangeNone = 0; @@ -169,14 +176,14 @@ message LayerState { frameNumberChanged = 0x02; cachedBufferChanged = 0x04; } - uint32 flags = 6; - uint64 cached_buffer_id = 7; + uint32 flags = 5; + uint64 cached_buffer_id = 6; } - BufferData buffer_data = 23; - int32 api = 24; - bool has_sideband_stream = 25; - ColorTransformProto color_transform = 26; - repeated BlurRegion blur_regions = 27; + BufferData buffer_data = 22; + int32 api = 23; + bool has_sideband_stream = 24; + ColorTransformProto color_transform = 25; + repeated BlurRegion blur_regions = 26; message Transform { float dsdx = 1; @@ -189,38 +196,38 @@ message LayerState { message WindowInfo { uint32 layout_params_flags = 1; int32 layout_params_type = 2; - RegionProto touchable_region = 4; - int32 surface_inset = 5; - bool focusable = 8; - bool has_wallpaper = 9; - float global_scale_factor = 10; - int32 crop_layer_id = 13; - bool replace_touchable_region_with_crop = 14; - RectProto touchable_region_crop = 15; - Transform transform = 16; + RegionProto touchable_region = 3; + int32 surface_inset = 4; + bool focusable = 5; + bool has_wallpaper = 6; + float global_scale_factor = 7; + int32 crop_layer_id = 8; + bool replace_touchable_region_with_crop = 9; + RectProto touchable_region_crop = 10; + Transform transform = 11; } - WindowInfo window_info_handle = 28; - float bg_color_alpha = 31; - int32 bg_color_dataspace = 32; - bool color_space_agnostic = 33; - float shadow_radius = 34; - int32 frame_rate_selection_priority = 35; - float frame_rate = 36; - int32 frame_rate_compatibility = 37; - int32 change_frame_rate_strategy = 38; - uint32 fixed_transform_hint = 39; - uint64 frame_number = 40; - bool auto_refresh = 41; - bool is_trusted_overlay = 42; - RectProto buffer_crop = 44; - RectProto destination_frame = 45; + WindowInfo window_info_handle = 27; + float bg_color_alpha = 28; + int32 bg_color_dataspace = 29; + bool color_space_agnostic = 30; + float shadow_radius = 31; + int32 frame_rate_selection_priority = 32; + float frame_rate = 33; + int32 frame_rate_compatibility = 34; + int32 change_frame_rate_strategy = 35; + uint32 fixed_transform_hint = 36; + uint64 frame_number = 37; + bool auto_refresh = 38; + bool is_trusted_overlay = 39; + RectProto buffer_crop = 40; + RectProto destination_frame = 41; enum DropInputMode { NONE = 0; ALL = 1; OBSCURED = 2; }; - DropInputMode drop_input_mode = 48; + DropInputMode drop_input_mode = 42; } message DisplayState { diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp index cebd4519b1..6e00748b45 100644 --- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp @@ -69,16 +69,16 @@ TEST(TransactionProtoParserTest, parse) { t1.displays.add(display); } - std::function&)> getLayerIdFn = [&](const sp& handle) { + TransactionProtoParser::LayerHandleToIdFn getLayerIdFn = [&](const sp& handle) { return (handle == layerHandle) ? 42 : -1; }; - std::function&)> getDisplayIdFn = [&](const sp& handle) { + TransactionProtoParser::DisplayHandleToIdFn getDisplayIdFn = [&](const sp& handle) { return (handle == displayHandle) ? 43 : -1; }; - std::function(int32_t)> getLayerHandleFn = [&](int32_t id) { + TransactionProtoParser::LayerIdToHandleFn getLayerHandleFn = [&](int32_t id) { return (id == 42) ? layerHandle : nullptr; }; - std::function(int32_t)> getDisplayHandleFn = [&](int32_t id) { + TransactionProtoParser::DisplayIdToHandleFn getDisplayHandleFn = [&](int32_t id) { return (id == 43) ? displayHandle : nullptr; }; -- cgit v1.2.3-59-g8ed1b From 3cfec7b162d40a53880f3cbaf863b0b39027db3d Mon Sep 17 00:00:00 2001 From: Antonio Kantek Date: Fri, 5 Nov 2021 18:26:17 -0700 Subject: TouchMode (6.2/n) Fully detaching touch mode from focus event (native) Bug: 193718270 Test: atest inputflinger_tests Test: atest libinput_tests Test: atest FrameworksCoreTests Test: atest CtsInputMethodTestCases Test: atest CtsInputTestCases Test: atest CtsSecurityTestCases Test: atest CtsWindowManagerDeviceTestCases Change-Id: I334c63d781ee8e8c13d21cc4a6cf323d885fc985 --- include/input/Input.h | 5 +---- include/input/InputTransport.h | 7 +++---- libs/input/Input.cpp | 4 +--- libs/input/InputTransport.cpp | 19 ++++++------------- libs/input/tests/InputPublisherAndConsumer_test.cpp | 4 +--- libs/input/tests/StructLayout_test.cpp | 3 +-- services/inputflinger/dispatcher/InputDispatcher.cpp | 3 +-- services/inputflinger/tests/InputDispatcher_test.cpp | 1 - 8 files changed, 14 insertions(+), 32 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index 7cc595a264..ce9cefed8b 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -840,15 +840,12 @@ public: inline bool getHasFocus() const { return mHasFocus; } - inline bool getInTouchMode() const { return mInTouchMode; } - - void initialize(int32_t id, bool hasFocus, bool inTouchMode); + void initialize(int32_t id, bool hasFocus); void initialize(const FocusEvent& from); protected: bool mHasFocus; - bool mInTouchMode; }; /* diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index d655b28278..edcb615491 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -178,10 +178,9 @@ struct InputMessage { struct Focus { int32_t eventId; - // The following 3 fields take up 4 bytes total + // The following 2 fields take up 4 bytes total bool hasFocus; - bool inTouchMode; - uint8_t empty[2]; + uint8_t empty[3]; inline size_t size() const { return sizeof(Focus); } } focus; @@ -381,7 +380,7 @@ public: * Returns DEAD_OBJECT if the channel's peer has been closed. * Other errors probably indicate that the channel is broken. */ - status_t publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus, bool inTouchMode); + status_t publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus); /* Publishes a capture event to the input channel. * diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 24a77209c4..c7f77d42fe 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -820,17 +820,15 @@ float MotionEvent::calculateTransformedAxisValue(int32_t axis, uint32_t source, // --- FocusEvent --- -void FocusEvent::initialize(int32_t id, bool hasFocus, bool inTouchMode) { +void FocusEvent::initialize(int32_t id, bool hasFocus) { InputEvent::initialize(id, ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, AINPUT_SOURCE_UNKNOWN, ADISPLAY_ID_NONE, INVALID_HMAC); mHasFocus = hasFocus; - mInTouchMode = inTouchMode; } void FocusEvent::initialize(const FocusEvent& from) { InputEvent::initialize(from); mHasFocus = from.mHasFocus; - mInTouchMode = from.mInTouchMode; } // --- CaptureEvent --- diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 02a5a0807b..a065ce25f7 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -278,7 +278,6 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const { case InputMessage::Type::FOCUS: { msg->body.focus.eventId = body.focus.eventId; msg->body.focus.hasFocus = body.focus.hasFocus; - msg->body.focus.inTouchMode = body.focus.inTouchMode; break; } case InputMessage::Type::CAPTURE: { @@ -622,13 +621,10 @@ status_t InputPublisher::publishMotionEvent( return mChannel->sendMessage(&msg); } -status_t InputPublisher::publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus, - bool inTouchMode) { +status_t InputPublisher::publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus) { if (ATRACE_ENABLED()) { - std::string message = - StringPrintf("publishFocusEvent(inputChannel=%s, hasFocus=%s, inTouchMode=%s)", - mChannel->getName().c_str(), toString(hasFocus), - toString(inTouchMode)); + std::string message = StringPrintf("publishFocusEvent(inputChannel=%s, hasFocus=%s)", + mChannel->getName().c_str(), toString(hasFocus)); ATRACE_NAME(message.c_str()); } @@ -637,7 +633,6 @@ status_t InputPublisher::publishFocusEvent(uint32_t seq, int32_t eventId, bool h msg.header.seq = seq; msg.body.focus.eventId = eventId; msg.body.focus.hasFocus = hasFocus; - msg.body.focus.inTouchMode = inTouchMode; return mChannel->sendMessage(&msg); } @@ -1371,8 +1366,7 @@ void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) } void InputConsumer::initializeFocusEvent(FocusEvent* event, const InputMessage* msg) { - event->initialize(msg->body.focus.eventId, msg->body.focus.hasFocus, - msg->body.focus.inTouchMode); + event->initialize(msg->body.focus.eventId, msg->body.focus.hasFocus); } void InputConsumer::initializeCaptureEvent(CaptureEvent* event, const InputMessage* msg) { @@ -1491,9 +1485,8 @@ std::string InputConsumer::dump() const { break; } case InputMessage::Type::FOCUS: { - out += android::base::StringPrintf("hasFocus=%s inTouchMode=%s", - toString(msg.body.focus.hasFocus), - toString(msg.body.focus.inTouchMode)); + out += android::base::StringPrintf("hasFocus=%s", + toString(msg.body.focus.hasFocus)); break; } case InputMessage::Type::CAPTURE: { diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index 973194c8f6..05bc0bcbe8 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -290,10 +290,9 @@ void InputPublisherAndConsumerTest::PublishAndConsumeFocusEvent() { constexpr uint32_t seq = 15; int32_t eventId = InputEvent::nextId(); constexpr bool hasFocus = true; - constexpr bool inTouchMode = true; const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC); - status = mPublisher->publishFocusEvent(seq, eventId, hasFocus, inTouchMode); + status = mPublisher->publishFocusEvent(seq, eventId, hasFocus); ASSERT_EQ(OK, status) << "publisher publishFocusEvent should return OK"; uint32_t consumeSeq; @@ -309,7 +308,6 @@ void InputPublisherAndConsumerTest::PublishAndConsumeFocusEvent() { EXPECT_EQ(seq, consumeSeq); EXPECT_EQ(eventId, focusEvent->getId()); EXPECT_EQ(hasFocus, focusEvent->getHasFocus()); - EXPECT_EQ(inTouchMode, focusEvent->getInTouchMode()); status = mConsumer->sendFinishedSignal(seq, true); ASSERT_EQ(OK, status) << "consumer sendFinishedSignal should return OK"; diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp index 2f88704d63..b6a94764e5 100644 --- a/libs/input/tests/StructLayout_test.cpp +++ b/libs/input/tests/StructLayout_test.cpp @@ -84,8 +84,7 @@ void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage::Body::Focus, eventId, 0); CHECK_OFFSET(InputMessage::Body::Focus, hasFocus, 4); - CHECK_OFFSET(InputMessage::Body::Focus, inTouchMode, 5); - CHECK_OFFSET(InputMessage::Body::Focus, empty, 6); + CHECK_OFFSET(InputMessage::Body::Focus, empty, 5); CHECK_OFFSET(InputMessage::Body::Capture, eventId, 0); CHECK_OFFSET(InputMessage::Body::Capture, pointerCaptureEnabled, 4); diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 695258759b..5c56e842db 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3234,8 +3234,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, const FocusEntry& focusEntry = static_cast(eventEntry); status = connection->inputPublisher.publishFocusEvent(dispatchEntry->seq, focusEntry.id, - focusEntry.hasFocus, - mInTouchMode); + focusEntry.hasFocus); break; } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index d8fd16c5e6..515a01e137 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -842,7 +842,6 @@ public: FocusEvent* focusEvent = static_cast(event); EXPECT_EQ(hasFocus, focusEvent->getHasFocus()); - EXPECT_EQ(inTouchMode, focusEvent->getInTouchMode()); } void consumeCaptureEvent(bool hasCapture) { -- cgit v1.2.3-59-g8ed1b From 4f1dd8a0a6188980462d36fe6ca0471cac8448b1 Mon Sep 17 00:00:00 2001 From: Arthur Ishiguro Date: Fri, 12 Nov 2021 17:21:24 +0000 Subject: Use std::vector in SensorDevice code Bug: 195593357 Test: Compile, verify CTS pass Change-Id: I665f52c1528fb0c9d9f4cd2368008773b06a65f1 --- services/sensorservice/SensorDevice.cpp | 4 ++-- services/sensorservice/SensorDevice.h | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp index db1a1cc29f..2a4ff653f7 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -338,8 +338,8 @@ void SensorDevice::reconnect() { mReconnecting = false; } -bool SensorDevice::sensorHandlesChanged(const Vector& oldSensorList, - const Vector& newSensorList) { +bool SensorDevice::sensorHandlesChanged(const std::vector& oldSensorList, + const std::vector& newSensorList) { bool didChange = false; if (oldSensorList.size() != newSensorList.size()) { diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h index bc8d20fbf6..e90a02ff2e 100644 --- a/services/sensorservice/SensorDevice.h +++ b/services/sensorservice/SensorDevice.h @@ -32,9 +32,10 @@ #include #include -#include -#include #include //std::max std::min +#include +#include +#include #include "RingBuffer.h" @@ -136,7 +137,7 @@ private: friend class Singleton; sp<::android::hardware::sensors::V2_1::implementation::ISensorsWrapperBase> mSensors; - Vector mSensorList; + std::vector mSensorList; std::unordered_map mConnectedDynamicSensors; // A bug in the Sensors HIDL spec which marks onDynamicSensorsConnected as oneway causes dynamic @@ -233,8 +234,8 @@ private: bool connectHidlService(); void initializeSensorList(); void reactivateSensors(const DefaultKeyedVector& previousActivations); - static bool sensorHandlesChanged(const Vector& oldSensorList, - const Vector& newSensorList); + static bool sensorHandlesChanged(const std::vector& oldSensorList, + const std::vector& newSensorList); static bool sensorIsEquivalent(const sensor_t& prevSensor, const sensor_t& newSensor); enum HalConnectionStatus { -- cgit v1.2.3-59-g8ed1b From 2fd90a7e0aa3ddb6aef9e25981d37a1a6d4fc868 Mon Sep 17 00:00:00 2001 From: Arthur Ishiguro Date: Fri, 12 Nov 2021 17:24:41 +0000 Subject: Remove unused variable in SensorService code Bug: 195593357 Test: Compile Change-Id: I763410d42e542dbe4876160adf95e540ee8c5dbe --- services/sensorservice/SensorService.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index 32a0110a72..9bc7b8e30e 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -164,7 +164,6 @@ void SensorService::onFirstRef() { sensor_t const* list; ssize_t count = dev.getSensorList(&list); if (count > 0) { - ssize_t orientationIndex = -1; bool hasGyro = false, hasAccel = false, hasMag = false; uint32_t virtualSensorsNeeds = (1< Date: Fri, 12 Nov 2021 12:13:20 -0800 Subject: Don't crash skiagl backend. The skiagl backend was incorrectly being created as skiaglthreaded, which breaks mapping ExternalTextures off-thread. Specifically, there is a workaround that disables mapping ExternalTextures at all when the skiagl backend is used. Don't break that workaround by propagating the renderengine type properly to implementations. Bug: 205591213 Bug: 196334700 Bug: 193212592 Test: `adb shell stop; adb shell setprop debug.renderengine.backend skiagl; adb shell start` boots Change-Id: I455d5d613ccaa210dc748969e025dc86c78080b8 --- libs/renderengine/RenderEngine.cpp | 36 ++++++---------------- .../include/renderengine/RenderEngine.h | 2 +- 2 files changed, 11 insertions(+), 27 deletions(-) diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp index a9ea690a7c..65d48951c6 100644 --- a/libs/renderengine/RenderEngine.cpp +++ b/libs/renderengine/RenderEngine.cpp @@ -26,55 +26,39 @@ namespace android { namespace renderengine { -std::unique_ptr RenderEngine::create(const RenderEngineCreationArgs& args) { - RenderEngineType renderEngineType = args.renderEngineType; - +std::unique_ptr RenderEngine::create(RenderEngineCreationArgs args) { // Keep the ability to override by PROPERTIES: char prop[PROPERTY_VALUE_MAX]; property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, ""); if (strcmp(prop, "gles") == 0) { - renderEngineType = RenderEngineType::GLES; + args.renderEngineType = RenderEngineType::GLES; } if (strcmp(prop, "threaded") == 0) { - renderEngineType = RenderEngineType::THREADED; + args.renderEngineType = RenderEngineType::THREADED; } if (strcmp(prop, "skiagl") == 0) { - renderEngineType = RenderEngineType::SKIA_GL; + args.renderEngineType = RenderEngineType::SKIA_GL; } if (strcmp(prop, "skiaglthreaded") == 0) { - renderEngineType = RenderEngineType::SKIA_GL_THREADED; + args.renderEngineType = RenderEngineType::SKIA_GL_THREADED; } - switch (renderEngineType) { + switch (args.renderEngineType) { case RenderEngineType::THREADED: ALOGD("Threaded RenderEngine with GLES Backend"); return renderengine::threaded::RenderEngineThreaded::create( [args]() { return android::renderengine::gl::GLESRenderEngine::create(args); }, - renderEngineType); + args.renderEngineType); case RenderEngineType::SKIA_GL: ALOGD("RenderEngine with SkiaGL Backend"); return renderengine::skia::SkiaGLRenderEngine::create(args); case RenderEngineType::SKIA_GL_THREADED: { - // These need to be recreated, since they are a constant reference, and we need to - // let SkiaRE know that it's running as threaded, and all GL operation will happen on - // the same thread. - RenderEngineCreationArgs skiaArgs = - RenderEngineCreationArgs::Builder() - .setPixelFormat(args.pixelFormat) - .setImageCacheSize(args.imageCacheSize) - .setUseColorManagerment(args.useColorManagement) - .setEnableProtectedContext(args.enableProtectedContext) - .setPrecacheToneMapperShaderOnly(args.precacheToneMapperShaderOnly) - .setSupportsBackgroundBlur(args.supportsBackgroundBlur) - .setContextPriority(args.contextPriority) - .setRenderEngineType(renderEngineType) - .build(); ALOGD("Threaded RenderEngine with SkiaGL Backend"); return renderengine::threaded::RenderEngineThreaded::create( - [skiaArgs]() { - return android::renderengine::skia::SkiaGLRenderEngine::create(skiaArgs); + [args]() { + return android::renderengine::skia::SkiaGLRenderEngine::create(args); }, - renderEngineType); + args.renderEngineType); } case RenderEngineType::GLES: default: diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index b9cc6485e5..6b85c57069 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -99,7 +99,7 @@ public: SKIA_GL_THREADED = 4, }; - static std::unique_ptr create(const RenderEngineCreationArgs& args); + static std::unique_ptr create(RenderEngineCreationArgs args); virtual ~RenderEngine() = 0; -- cgit v1.2.3-59-g8ed1b From d6b9e21ecfa03438daff759cf35c040b754a5b93 Mon Sep 17 00:00:00 2001 From: Arthur Ishiguro Date: Sun, 14 Nov 2021 01:20:55 +0000 Subject: Run clang-format on SensorDevice code Bug: 195593357 Test: Compile Change-Id: Ia551f179cee658d4aa2c1587e380e6a1a1763d91 --- services/sensorservice/SensorDevice.cpp | 471 +++++++++++++++----------------- services/sensorservice/SensorDevice.h | 90 +++--- 2 files changed, 269 insertions(+), 292 deletions(-) diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp index 2a4ff653f7..49c5c2372d 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -23,31 +23,31 @@ #include #include +#include #include #include -#include #include #include -#include #include #include +#include #include using namespace android::hardware::sensors; using namespace android::hardware::sensors::V1_0; using namespace android::hardware::sensors::V1_0::implementation; +using android::hardware::hidl_vec; +using android::hardware::Return; using android::hardware::sensors::V2_0::EventQueueFlagBits; using android::hardware::sensors::V2_0::WakeLockQueueFlagBits; using android::hardware::sensors::V2_1::ISensorsCallback; -using android::hardware::sensors::V2_1::implementation::convertToOldSensorInfo; -using android::hardware::sensors::V2_1::implementation::convertToNewSensorInfos; using android::hardware::sensors::V2_1::implementation::convertToNewEvents; +using android::hardware::sensors::V2_1::implementation::convertToNewSensorInfos; +using android::hardware::sensors::V2_1::implementation::convertToOldSensorInfo; using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV1_0; using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV2_0; using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV2_1; -using android::hardware::hidl_vec; -using android::hardware::Return; using android::SensorDeviceUtils::HidlServiceRegistrationWaiter; using android::util::ProtoOutputStream; @@ -73,7 +73,7 @@ status_t statusFromResult(Result result) { } } -template +template constexpr typename std::underlying_type::type asBaseType(EnumType value) { return static_cast::type>(value); } @@ -81,14 +81,13 @@ constexpr typename std::underlying_type::type asBaseType(EnumType valu // Used internally by the framework to wake the Event FMQ. These values must start after // the last value of EventQueueFlagBits enum EventQueueFlagBitsInternal : uint32_t { - INTERNAL_WAKE = 1 << 16, + INTERNAL_WAKE = 1 << 16, }; -} // anonymous namespace +} // anonymous namespace void SensorsHalDeathReceivier::serviceDied( - uint64_t /* cookie */, - const wp<::android::hidl::base::V1_0::IBase>& /* service */) { + uint64_t /* cookie */, const wp<::android::hidl::base::V1_0::IBase>& /* service */) { ALOGW("Sensors HAL died, attempting to reconnect."); SensorDevice::getInstance().prepareForReconnect(); } @@ -98,29 +97,29 @@ struct SensorsCallback : public ISensorsCallback { using SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo; Return onDynamicSensorsConnected_2_1( - const hidl_vec &dynamicSensorsAdded) override { + const hidl_vec& dynamicSensorsAdded) override { return SensorDevice::getInstance().onDynamicSensorsConnected(dynamicSensorsAdded); } Return onDynamicSensorsConnected( - const hidl_vec &dynamicSensorsAdded) override { + const hidl_vec& dynamicSensorsAdded) override { return SensorDevice::getInstance().onDynamicSensorsConnected( convertToNewSensorInfos(dynamicSensorsAdded)); } Return onDynamicSensorsDisconnected( - const hidl_vec &dynamicSensorHandlesRemoved) override { + const hidl_vec& dynamicSensorHandlesRemoved) override { return SensorDevice::getInstance().onDynamicSensorsDisconnected( dynamicSensorHandlesRemoved); } }; SensorDevice::SensorDevice() - : mHidlTransportErrors(20), - mRestartWaiter(new HidlServiceRegistrationWaiter()), - mEventQueueFlag(nullptr), - mWakeLockQueueFlag(nullptr), - mReconnecting(false) { + : mHidlTransportErrors(20), + mRestartWaiter(new HidlServiceRegistrationWaiter()), + mEventQueueFlag(nullptr), + mWakeLockQueueFlag(nullptr), + mReconnecting(false) { if (!connectHidlService()) { return; } @@ -132,61 +131,59 @@ SensorDevice::SensorDevice() } void SensorDevice::initializeSensorList() { - checkReturn(mSensors->getSensorsList( - [&](const auto &list) { - const size_t count = list.size(); - - mActivationCount.setCapacity(count); - Info model; - for (size_t i=0 ; i < count; i++) { - sensor_t sensor; - convertToSensor(convertToOldSensorInfo(list[i]), &sensor); - - if (sensor.type < static_cast(SensorType::DEVICE_PRIVATE_BASE)) { - sensor.resolution = SensorDeviceUtils::resolutionForSensor(sensor); - - // Some sensors don't have a default resolution and will be left at 0. - // Don't crash in this case since CTS will verify that devices don't go to - // production with a resolution of 0. - if (sensor.resolution != 0) { - float quantizedRange = sensor.maxRange; - SensorDeviceUtils::quantizeValue( - &quantizedRange, sensor.resolution, /*factor=*/ 1); - // Only rewrite maxRange if the requantization produced a "significant" - // change, which is fairly arbitrarily defined as resolution / 8. - // Smaller deltas are permitted, as they may simply be due to floating - // point representation error, etc. - if (fabsf(sensor.maxRange - quantizedRange) > sensor.resolution / 8) { - ALOGW("%s's max range %.12f is not a multiple of the resolution " - "%.12f - updated to %.12f", sensor.name, sensor.maxRange, - sensor.resolution, quantizedRange); - sensor.maxRange = quantizedRange; - } - } else { - // Don't crash here or the device will go into a crashloop. - ALOGW("%s should have a non-zero resolution", sensor.name); - } - } + checkReturn(mSensors->getSensorsList([&](const auto& list) { + const size_t count = list.size(); - // Check and clamp power if it is 0 (or close) - constexpr float MIN_POWER_MA = 0.001; // 1 microAmp - if (sensor.power < MIN_POWER_MA) { - ALOGI("%s's reported power %f invalid, clamped to %f", - sensor.name, sensor.power, MIN_POWER_MA); - sensor.power = MIN_POWER_MA; + mActivationCount.setCapacity(count); + Info model; + for (size_t i = 0; i < count; i++) { + sensor_t sensor; + convertToSensor(convertToOldSensorInfo(list[i]), &sensor); + + if (sensor.type < static_cast(SensorType::DEVICE_PRIVATE_BASE)) { + sensor.resolution = SensorDeviceUtils::resolutionForSensor(sensor); + + // Some sensors don't have a default resolution and will be left at 0. + // Don't crash in this case since CTS will verify that devices don't go to + // production with a resolution of 0. + if (sensor.resolution != 0) { + float quantizedRange = sensor.maxRange; + SensorDeviceUtils::quantizeValue(&quantizedRange, sensor.resolution, + /*factor=*/1); + // Only rewrite maxRange if the requantization produced a "significant" + // change, which is fairly arbitrarily defined as resolution / 8. + // Smaller deltas are permitted, as they may simply be due to floating + // point representation error, etc. + if (fabsf(sensor.maxRange - quantizedRange) > sensor.resolution / 8) { + ALOGW("%s's max range %.12f is not a multiple of the resolution " + "%.12f - updated to %.12f", + sensor.name, sensor.maxRange, sensor.resolution, quantizedRange); + sensor.maxRange = quantizedRange; } - mSensorList.push_back(sensor); + } else { + // Don't crash here or the device will go into a crashloop. + ALOGW("%s should have a non-zero resolution", sensor.name); + } + } + + // Check and clamp power if it is 0 (or close) + constexpr float MIN_POWER_MA = 0.001; // 1 microAmp + if (sensor.power < MIN_POWER_MA) { + ALOGI("%s's reported power %f invalid, clamped to %f", sensor.name, sensor.power, + MIN_POWER_MA); + sensor.power = MIN_POWER_MA; + } + mSensorList.push_back(sensor); - mActivationCount.add(list[i].sensorHandle, model); + mActivationCount.add(list[i].sensorHandle, model); - // Only disable all sensors on HAL 1.0 since HAL 2.0 - // handles this in its initialize method - if (!mSensors->supportsMessageQueues()) { - checkReturn(mSensors->activate(list[i].sensorHandle, - 0 /* enabled */)); - } - } - })); + // Only disable all sensors on HAL 1.0 since HAL 2.0 + // handles this in its initialize method + if (!mSensors->supportsMessageQueues()) { + checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */)); + } + } + })); } SensorDevice::~SensorDevice() { @@ -231,7 +228,7 @@ SensorDevice::HalConnectionStatus SensorDevice::connectHidlServiceV1_0() { // Poke ISensor service. If it has lingering connection from previous generation of // system server, it will kill itself. There is no intention to handle the poll result, // which will be done since the size is 0. - if(mSensors->poll(0, [](auto, const auto &, const auto &) {}).isOk()) { + if (mSensors->poll(0, [](auto, const auto&, const auto&) {}).isOk()) { // ok to continue connectionStatus = HalConnectionStatus::CONNECTED; break; @@ -278,23 +275,22 @@ SensorDevice::HalConnectionStatus SensorDevice::connectHidlServiceV2_1() { SensorDevice::HalConnectionStatus SensorDevice::initializeHidlServiceV2_X() { HalConnectionStatus connectionStatus = HalConnectionStatus::UNKNOWN; - mWakeLockQueue = std::make_unique( - SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT, - true /* configureEventFlagWord */); + mWakeLockQueue = + std::make_unique(SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT, + true /* configureEventFlagWord */); hardware::EventFlag::deleteEventFlag(&mEventQueueFlag); - hardware::EventFlag::createEventFlag(mSensors->getEventQueue()->getEventFlagWord(), &mEventQueueFlag); + hardware::EventFlag::createEventFlag(mSensors->getEventQueue()->getEventFlagWord(), + &mEventQueueFlag); hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag); - hardware::EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), - &mWakeLockQueueFlag); + hardware::EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), &mWakeLockQueueFlag); - CHECK(mSensors != nullptr && mWakeLockQueue != nullptr && - mEventQueueFlag != nullptr && mWakeLockQueueFlag != nullptr); + CHECK(mSensors != nullptr && mWakeLockQueue != nullptr && mEventQueueFlag != nullptr && + mWakeLockQueueFlag != nullptr); - status_t status = checkReturnAndGetStatus(mSensors->initialize( - *mWakeLockQueue->getDesc(), - new SensorsCallback())); + status_t status = checkReturnAndGetStatus( + mSensors->initialize(*mWakeLockQueue->getDesc(), new SensorsCallback())); if (status != NO_ERROR) { connectionStatus = HalConnectionStatus::FAILED_TO_CONNECT; @@ -375,19 +371,17 @@ bool SensorDevice::sensorHandlesChanged(const std::vector& oldSensorLi bool SensorDevice::sensorIsEquivalent(const sensor_t& prevSensor, const sensor_t& newSensor) { bool equivalent = true; if (prevSensor.handle != newSensor.handle || - (strcmp(prevSensor.vendor, newSensor.vendor) != 0) || - (strcmp(prevSensor.stringType, newSensor.stringType) != 0) || - (strcmp(prevSensor.requiredPermission, newSensor.requiredPermission) != 0) || - (prevSensor.version != newSensor.version) || - (prevSensor.type != newSensor.type) || - (std::abs(prevSensor.maxRange - newSensor.maxRange) > 0.001f) || - (std::abs(prevSensor.resolution - newSensor.resolution) > 0.001f) || - (std::abs(prevSensor.power - newSensor.power) > 0.001f) || - (prevSensor.minDelay != newSensor.minDelay) || - (prevSensor.fifoReservedEventCount != newSensor.fifoReservedEventCount) || - (prevSensor.fifoMaxEventCount != newSensor.fifoMaxEventCount) || - (prevSensor.maxDelay != newSensor.maxDelay) || - (prevSensor.flags != newSensor.flags)) { + (strcmp(prevSensor.vendor, newSensor.vendor) != 0) || + (strcmp(prevSensor.stringType, newSensor.stringType) != 0) || + (strcmp(prevSensor.requiredPermission, newSensor.requiredPermission) != 0) || + (prevSensor.version != newSensor.version) || (prevSensor.type != newSensor.type) || + (std::abs(prevSensor.maxRange - newSensor.maxRange) > 0.001f) || + (std::abs(prevSensor.resolution - newSensor.resolution) > 0.001f) || + (std::abs(prevSensor.power - newSensor.power) > 0.001f) || + (prevSensor.minDelay != newSensor.minDelay) || + (prevSensor.fifoReservedEventCount != newSensor.fifoReservedEventCount) || + (prevSensor.fifoMaxEventCount != newSensor.fifoMaxEventCount) || + (prevSensor.maxDelay != newSensor.maxDelay) || (prevSensor.flags != newSensor.flags)) { equivalent = false; } return equivalent; @@ -405,7 +399,7 @@ void SensorDevice::reactivateSensors(const DefaultKeyedVector& previo for (size_t j = 0; j < info.batchParams.size(); j++) { const BatchParams& batchParams = info.batchParams[j]; status_t res = batchLocked(info.batchParams.keyAt(j), handle, 0 /* flags */, - batchParams.mTSample, batchParams.mTBatch); + batchParams.mTSample, batchParams.mTBatch); if (res == NO_ERROR) { activateLocked(info.batchParams.keyAt(j), handle, true /* enabled */); @@ -433,7 +427,7 @@ std::string SensorDevice::dump() const { mSensorList.size(), mActivationCount.size(), mDisabledClients.size()); Mutex::Autolock _l(mLock); - for (const auto & s : mSensorList) { + for (const auto& s : mSensorList) { int32_t handle = s.handle; const Info& info = mActivationCount.valueFor(handle); if (info.numActiveClients() == 0) continue; @@ -444,8 +438,9 @@ std::string SensorDevice::dump() const { for (size_t j = 0; j < info.batchParams.size(); j++) { const BatchParams& params = info.batchParams[j]; result.appendFormat("%.1f%s%s", params.mTSample / 1e6f, - isClientDisabledLocked(info.batchParams.keyAt(j)) ? "(disabled)" : "", - (j < info.batchParams.size() - 1) ? ", " : ""); + isClientDisabledLocked(info.batchParams.keyAt(j)) ? "(disabled)" + : "", + (j < info.batchParams.size() - 1) ? ", " : ""); } result.appendFormat("}, selected = %.2f ms; ", info.bestBatchParams.mTSample / 1e6f); @@ -453,8 +448,9 @@ std::string SensorDevice::dump() const { for (size_t j = 0; j < info.batchParams.size(); j++) { const BatchParams& params = info.batchParams[j]; result.appendFormat("%.1f%s%s", params.mTBatch / 1e6f, - isClientDisabledLocked(info.batchParams.keyAt(j)) ? "(disabled)" : "", - (j < info.batchParams.size() - 1) ? ", " : ""); + isClientDisabledLocked(info.batchParams.keyAt(j)) ? "(disabled)" + : "", + (j < info.batchParams.size() - 1) ? ", " : ""); } result.appendFormat("}, selected = %.2f ms\n", info.bestBatchParams.mTBatch / 1e6f); } @@ -472,29 +468,29 @@ std::string SensorDevice::dump() const { void SensorDevice::dump(ProtoOutputStream* proto) const { using namespace service::SensorDeviceProto; if (mSensors == nullptr) { - proto->write(INITIALIZED , false); + proto->write(INITIALIZED, false); return; } - proto->write(INITIALIZED , true); - proto->write(TOTAL_SENSORS , int(mSensorList.size())); - proto->write(ACTIVE_SENSORS , int(mActivationCount.size())); + proto->write(INITIALIZED, true); + proto->write(TOTAL_SENSORS, int(mSensorList.size())); + proto->write(ACTIVE_SENSORS, int(mActivationCount.size())); Mutex::Autolock _l(mLock); - for (const auto & s : mSensorList) { + for (const auto& s : mSensorList) { int32_t handle = s.handle; const Info& info = mActivationCount.valueFor(handle); if (info.numActiveClients() == 0) continue; uint64_t token = proto->start(SENSORS); - proto->write(SensorProto::HANDLE , handle); - proto->write(SensorProto::ACTIVE_COUNT , int(info.batchParams.size())); + proto->write(SensorProto::HANDLE, handle); + proto->write(SensorProto::ACTIVE_COUNT, int(info.batchParams.size())); for (size_t j = 0; j < info.batchParams.size(); j++) { const BatchParams& params = info.batchParams[j]; - proto->write(SensorProto::SAMPLING_PERIOD_MS , params.mTSample / 1e6f); - proto->write(SensorProto::BATCHING_PERIOD_MS , params.mTBatch / 1e6f); + proto->write(SensorProto::SAMPLING_PERIOD_MS, params.mTSample / 1e6f); + proto->write(SensorProto::BATCHING_PERIOD_MS, params.mTBatch / 1e6f); } - proto->write(SensorProto::SAMPLING_PERIOD_SELECTED , info.bestBatchParams.mTSample / 1e6f); - proto->write(SensorProto::BATCHING_PERIOD_SELECTED , info.bestBatchParams.mTBatch / 1e6f); + proto->write(SensorProto::SAMPLING_PERIOD_SELECTED, info.bestBatchParams.mTSample / 1e6f); + proto->write(SensorProto::BATCHING_PERIOD_SELECTED, info.bestBatchParams.mTBatch / 1e6f); proto->end(token); } } @@ -531,20 +527,19 @@ ssize_t SensorDevice::pollHal(sensors_event_t* buffer, size_t count) { do { auto ret = mSensors->poll( - count, - [&](auto result, - const auto &events, - const auto &dynamicSensorsAdded) { + count, [&](auto result, const auto& events, const auto& dynamicSensorsAdded) { if (result == Result::OK) { convertToSensorEventsAndQuantize(convertToNewEvents(events), - convertToNewSensorInfos(dynamicSensorsAdded), buffer); + convertToNewSensorInfos( + dynamicSensorsAdded), + buffer); err = (ssize_t)events.size(); } else { err = statusFromResult(result); } }); - if (ret.isOk()) { + if (ret.isOk()) { hidlTransportError = false; } else { hidlTransportError = true; @@ -559,7 +554,7 @@ ssize_t SensorDevice::pollHal(sensors_event_t* buffer, size_t count) { } } while (hidlTransportError); - if(numHidlTransportErrors > 0) { + if (numHidlTransportErrors > 0) { ALOGE("Saw %d Hidl transport failures", numHidlTransportErrors); HidlTransportErrorLog errLog(time(nullptr), numHidlTransportErrors); mHidlTransportErrors.add(errLog); @@ -581,7 +576,8 @@ ssize_t SensorDevice::pollFmq(sensors_event_t* buffer, size_t maxNumEventsToRead // events is not available, then read() would return no events, possibly introducing // additional latency in delivering events to applications. mEventQueueFlag->wait(asBaseType(EventQueueFlagBits::READ_AND_PROCESS) | - asBaseType(INTERNAL_WAKE), &eventFlagState); + asBaseType(INTERNAL_WAKE), + &eventFlagState); availableEvents = mSensors->getEventQueue()->availableToRead(); if ((eventFlagState & asBaseType(INTERNAL_WAKE)) && mReconnecting) { @@ -600,12 +596,13 @@ ssize_t SensorDevice::pollFmq(sensors_event_t* buffer, size_t maxNumEventsToRead for (size_t i = 0; i < eventsToRead; i++) { convertToSensorEvent(mEventBuffer[i], &buffer[i]); android::SensorDeviceUtils::quantizeSensorEventValues(&buffer[i], - getResolutionForSensor(buffer[i].sensor)); + getResolutionForSensor( + buffer[i].sensor)); } eventsRead = eventsToRead; } else { - ALOGW("Failed to read %zu events, currently %zu events available", - eventsToRead, availableEvents); + ALOGW("Failed to read %zu events, currently %zu events available", eventsToRead, + availableEvents); } } @@ -613,22 +610,21 @@ ssize_t SensorDevice::pollFmq(sensors_event_t* buffer, size_t maxNumEventsToRead } Return SensorDevice::onDynamicSensorsConnected( - const hidl_vec &dynamicSensorsAdded) { + const hidl_vec& dynamicSensorsAdded) { std::unique_lock lock(mDynamicSensorsMutex); // Allocate a sensor_t structure for each dynamic sensor added and insert // it into the dictionary of connected dynamic sensors keyed by handle. for (size_t i = 0; i < dynamicSensorsAdded.size(); ++i) { - const SensorInfo &info = dynamicSensorsAdded[i]; + const SensorInfo& info = dynamicSensorsAdded[i]; auto it = mConnectedDynamicSensors.find(info.sensorHandle); CHECK(it == mConnectedDynamicSensors.end()); - sensor_t *sensor = new sensor_t(); + sensor_t* sensor = new sensor_t(); convertToSensor(convertToOldSensorInfo(info), sensor); - mConnectedDynamicSensors.insert( - std::make_pair(sensor->handle, sensor)); + mConnectedDynamicSensors.insert(std::make_pair(sensor->handle, sensor)); } mDynamicSensorsCv.notify_all(); @@ -637,8 +633,8 @@ Return SensorDevice::onDynamicSensorsConnected( } Return SensorDevice::onDynamicSensorsDisconnected( - const hidl_vec &dynamicSensorHandlesRemoved) { - (void) dynamicSensorHandlesRemoved; + const hidl_vec& dynamicSensorHandlesRemoved) { + (void)dynamicSensorHandlesRemoved; // TODO: Currently dynamic sensors do not seem to be removed return Return(); } @@ -653,7 +649,7 @@ void SensorDevice::writeWakeLockHandled(uint32_t count) { } } -void SensorDevice::autoDisable(void *ident, int handle) { +void SensorDevice::autoDisable(void* ident, int handle) { Mutex::Autolock _l(mLock); ssize_t activationIndex = mActivationCount.indexOfKey(handle); if (activationIndex < 0) { @@ -687,15 +683,15 @@ status_t SensorDevice::activateLocked(void* ident, int handle, int enabled) { Info& info(mActivationCount.editValueAt(activationIndex)); ALOGD_IF(DEBUG_CONNECTIONS, - "SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%zu", - ident, handle, enabled, info.batchParams.size()); + "SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%zu", ident, + handle, enabled, info.batchParams.size()); if (enabled) { ALOGD_IF(DEBUG_CONNECTIONS, "enable index=%zd", info.batchParams.indexOfKey(ident)); if (isClientDisabledLocked(ident)) { - ALOGW("SensorDevice::activate, isClientDisabledLocked(%p):true, handle:%d", - ident, handle); + ALOGW("SensorDevice::activate, isClientDisabledLocked(%p):true, handle:%d", ident, + handle); return NO_ERROR; } @@ -726,11 +722,10 @@ status_t SensorDevice::activateLocked(void* ident, int handle, int enabled) { // Call batch for this sensor with the previously calculated best effort // batch_rate and timeout. One of the apps has unregistered for sensor // events, and the best effort batch parameters might have changed. - ALOGD_IF(DEBUG_CONNECTIONS, - "\t>>> actuating h/w batch 0x%08x %" PRId64 " %" PRId64, handle, - info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch); - checkReturn(mSensors->batch( - handle, info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch)); + ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w batch 0x%08x %" PRId64 " %" PRId64, + handle, info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch); + checkReturn(mSensors->batch(handle, info.bestBatchParams.mTSample, + info.bestBatchParams.mTBatch)); } } else { // sensor wasn't enabled for this ident @@ -767,12 +762,8 @@ status_t SensorDevice::doActivateHardwareLocked(int handle, bool enabled) { return err; } -status_t SensorDevice::batch( - void* ident, - int handle, - int flags, - int64_t samplingPeriodNs, - int64_t maxBatchReportLatencyNs) { +status_t SensorDevice::batch(void* ident, int handle, int flags, int64_t samplingPeriodNs, + int64_t maxBatchReportLatencyNs) { if (mSensors == nullptr) return NO_INIT; if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) { @@ -783,7 +774,8 @@ status_t SensorDevice::batch( } ALOGD_IF(DEBUG_CONNECTIONS, - "SensorDevice::batch: ident=%p, handle=0x%08x, flags=%d, period_ns=%" PRId64 " timeout=%" PRId64, + "SensorDevice::batch: ident=%p, handle=0x%08x, flags=%d, period_ns=%" PRId64 + " timeout=%" PRId64, ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs); Mutex::Autolock _l(mLock); @@ -807,25 +799,24 @@ status_t SensorDevice::batchLocked(void* ident, int handle, int flags, int64_t s info.setBatchParamsForIdent(ident, flags, samplingPeriodNs, maxBatchReportLatencyNs); } - status_t err = updateBatchParamsLocked(handle, info); + status_t err = updateBatchParamsLocked(handle, info); if (err != NO_ERROR) { - ALOGE("sensor batch failed %p 0x%08x %" PRId64 " %" PRId64 " err=%s", - mSensors.get(), handle, info.bestBatchParams.mTSample, - info.bestBatchParams.mTBatch, strerror(-err)); + ALOGE("sensor batch failed %p 0x%08x %" PRId64 " %" PRId64 " err=%s", mSensors.get(), + handle, info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch, strerror(-err)); info.removeBatchParamsForIdent(ident); } return err; } -status_t SensorDevice::updateBatchParamsLocked(int handle, Info &info) { +status_t SensorDevice::updateBatchParamsLocked(int handle, Info& info) { BatchParams prevBestBatchParams = info.bestBatchParams; // Find the minimum of all timeouts and batch_rates for this sensor. info.selectBatchParams(); ALOGD_IF(DEBUG_CONNECTIONS, - "\t>>> curr_period=%" PRId64 " min_period=%" PRId64 - " curr_timeout=%" PRId64 " min_timeout=%" PRId64, + "\t>>> curr_period=%" PRId64 " min_period=%" PRId64 " curr_timeout=%" PRId64 + " min_timeout=%" PRId64, prevBestBatchParams.mTSample, info.bestBatchParams.mTSample, prevBestBatchParams.mTBatch, info.bestBatchParams.mTBatch); @@ -834,8 +825,8 @@ status_t SensorDevice::updateBatchParamsLocked(int handle, Info &info) { if (prevBestBatchParams != info.bestBatchParams && info.numActiveClients() > 0) { ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w BATCH 0x%08x %" PRId64 " %" PRId64, handle, info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch); - err = checkReturnAndGetStatus(mSensors->batch( - handle, info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch)); + err = checkReturnAndGetStatus(mSensors->batch(handle, info.bestBatchParams.mTSample, + info.bestBatchParams.mTBatch)); } return err; @@ -866,8 +857,8 @@ bool SensorDevice::isClientDisabledLocked(void* ident) const { return mDisabledClients.count(ident) > 0; } -std::vector SensorDevice::getDisabledClientsLocked() const { - std::vector vec; +std::vector SensorDevice::getDisabledClientsLocked() const { + std::vector vec; for (const auto& it : mDisabledClients) { vec.push_back(it.first); } @@ -896,7 +887,7 @@ void SensorDevice::setUidStateForConnection(void* ident, SensorService::UidState addDisabledReasonForIdentLocked(ident, DisabledReason::DISABLED_REASON_UID_IDLE); } - for (size_t i = 0; i< mActivationCount.size(); ++i) { + for (size_t i = 0; i < mActivationCount.size(); ++i) { int handle = mActivationCount.keyAt(i); Info& info = mActivationCount.editValueAt(i); @@ -905,8 +896,7 @@ void SensorDevice::setUidStateForConnection(void* ident, SensorService::UidState bool disable = info.numActiveClients() == 0 && info.isActive; bool enable = info.numActiveClients() > 0 && !info.isActive; - if ((enable || disable) && - doActivateHardwareLocked(handle, enable) == NO_ERROR) { + if ((enable || disable) && doActivateHardwareLocked(handle, enable) == NO_ERROR) { info.isActive = enable; } } @@ -941,22 +931,21 @@ void SensorDevice::enableAllSensors() { if (mSensors == nullptr) return; Mutex::Autolock _l(mLock); - for (void *client : getDisabledClientsLocked()) { - removeDisabledReasonForIdentLocked( - client, DisabledReason::DISABLED_REASON_SERVICE_RESTRICTED); + for (void* client : getDisabledClientsLocked()) { + removeDisabledReasonForIdentLocked(client, + DisabledReason::DISABLED_REASON_SERVICE_RESTRICTED); } - for (size_t i = 0; i< mActivationCount.size(); ++i) { + for (size_t i = 0; i < mActivationCount.size(); ++i) { Info& info = mActivationCount.editValueAt(i); if (info.batchParams.isEmpty()) continue; info.selectBatchParams(); const int sensor_handle = mActivationCount.keyAt(i); ALOGD_IF(DEBUG_CONNECTIONS, "\t>> reenable actuating h/w sensor enable handle=%d ", - sensor_handle); - status_t err = checkReturnAndGetStatus(mSensors->batch( - sensor_handle, - info.bestBatchParams.mTSample, - info.bestBatchParams.mTBatch)); + sensor_handle); + status_t err = checkReturnAndGetStatus(mSensors->batch(sensor_handle, + info.bestBatchParams.mTSample, + info.bestBatchParams.mTBatch)); ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err)); if (err == NO_ERROR) { @@ -973,38 +962,36 @@ void SensorDevice::enableAllSensors() { void SensorDevice::disableAllSensors() { if (mSensors == nullptr) return; Mutex::Autolock _l(mLock); - for (size_t i = 0; i< mActivationCount.size(); ++i) { + for (size_t i = 0; i < mActivationCount.size(); ++i) { Info& info = mActivationCount.editValueAt(i); // Check if this sensor has been activated previously and disable it. if (info.batchParams.size() > 0) { - const int sensor_handle = mActivationCount.keyAt(i); - ALOGD_IF(DEBUG_CONNECTIONS, "\t>> actuating h/w sensor disable handle=%d ", - sensor_handle); - checkReturn(mSensors->activate(sensor_handle, 0 /* enabled */)); - - // Add all the connections that were registered for this sensor to the disabled - // clients list. - for (size_t j = 0; j < info.batchParams.size(); ++j) { - addDisabledReasonForIdentLocked( - info.batchParams.keyAt(j), DisabledReason::DISABLED_REASON_SERVICE_RESTRICTED); - ALOGI("added %p to mDisabledClients", info.batchParams.keyAt(j)); - } - - info.isActive = false; + const int sensor_handle = mActivationCount.keyAt(i); + ALOGD_IF(DEBUG_CONNECTIONS, "\t>> actuating h/w sensor disable handle=%d ", + sensor_handle); + checkReturn(mSensors->activate(sensor_handle, 0 /* enabled */)); + + // Add all the connections that were registered for this sensor to the disabled + // clients list. + for (size_t j = 0; j < info.batchParams.size(); ++j) { + addDisabledReasonForIdentLocked(info.batchParams.keyAt(j), + DisabledReason::DISABLED_REASON_SERVICE_RESTRICTED); + ALOGI("added %p to mDisabledClients", info.batchParams.keyAt(j)); + } + + info.isActive = false; } } } -status_t SensorDevice::injectSensorData( - const sensors_event_t *injected_sensor_event) { +status_t SensorDevice::injectSensorData(const sensors_event_t* injected_sensor_event) { if (mSensors == nullptr) return NO_INIT; ALOGD_IF(DEBUG_CONNECTIONS, - "sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f", - injected_sensor_event->sensor, - injected_sensor_event->timestamp, injected_sensor_event->data[0], - injected_sensor_event->data[1], injected_sensor_event->data[2], - injected_sensor_event->data[3], injected_sensor_event->data[4], - injected_sensor_event->data[5]); + "sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f", + injected_sensor_event->sensor, injected_sensor_event->timestamp, + injected_sensor_event->data[0], injected_sensor_event->data[1], + injected_sensor_event->data[2], injected_sensor_event->data[3], + injected_sensor_event->data[4], injected_sensor_event->data[5]); Event ev; V2_1::implementation::convertFromSensorEvent(*injected_sensor_event, &ev); @@ -1014,8 +1001,8 @@ status_t SensorDevice::injectSensorData( status_t SensorDevice::setMode(uint32_t mode) { if (mSensors == nullptr) return NO_INIT; - return checkReturnAndGetStatus(mSensors->setOperationMode( - static_cast(mode))); + return checkReturnAndGetStatus( + mSensors->setOperationMode(static_cast(mode))); } int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) { @@ -1041,21 +1028,20 @@ int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) format = SharedMemFormat::SENSORS_EVENT; SharedMemInfo mem = { - .type = type, - .format = format, - .size = static_cast(memory->size), - .memoryHandle = memory->handle, + .type = type, + .format = format, + .size = static_cast(memory->size), + .memoryHandle = memory->handle, }; int32_t ret; - checkReturn(mSensors->registerDirectChannel(mem, - [&ret](auto result, auto channelHandle) { - if (result == Result::OK) { - ret = channelHandle; - } else { - ret = statusFromResult(result); - } - })); + checkReturn(mSensors->registerDirectChannel(mem, [&ret](auto result, auto channelHandle) { + if (result == Result::OK) { + ret = channelHandle; + } else { + ret = statusFromResult(result); + } + })); return ret; } @@ -1065,13 +1051,13 @@ void SensorDevice::unregisterDirectChannel(int32_t channelHandle) { checkReturn(mSensors->unregisterDirectChannel(channelHandle)); } -int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle, - int32_t channelHandle, const struct sensors_direct_cfg_t *config) { +int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle, int32_t channelHandle, + const struct sensors_direct_cfg_t* config) { if (mSensors == nullptr) return NO_INIT; Mutex::Autolock _l(mLock); RateLevel rate; - switch(config->rate_level) { + switch (config->rate_level) { case SENSOR_DIRECT_RATE_STOP: rate = RateLevel::STOP; break; @@ -1090,17 +1076,17 @@ int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle, int32_t ret; checkReturn(mSensors->configDirectReport(sensorHandle, channelHandle, rate, - [&ret, rate] (auto result, auto token) { - if (rate == RateLevel::STOP) { - ret = statusFromResult(result); - } else { - if (result == Result::OK) { - ret = token; - } else { - ret = statusFromResult(result); - } - } - })); + [&ret, rate](auto result, auto token) { + if (rate == RateLevel::STOP) { + ret = statusFromResult(result); + } else { + if (result == Result::OK) { + ret = token; + } else { + ret = statusFromResult(result); + } + } + })); return ret; } @@ -1118,13 +1104,12 @@ int SensorDevice::Info::numActiveClients() const { return num; } -status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int, - int64_t samplingPeriodNs, +status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int, int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs) { ssize_t index = batchParams.indexOfKey(ident); if (index < 0) { - ALOGE("Info::setBatchParamsForIdent(ident=%p, period_ns=%" PRId64 - " timeout=%" PRId64 ") failed (%s)", + ALOGE("Info::setBatchParamsForIdent(ident=%p, period_ns=%" PRId64 " timeout=%" PRId64 + ") failed (%s)", ident, samplingPeriodNs, maxBatchReportLatencyNs, strerror(-index)); return BAD_INDEX; } @@ -1168,12 +1153,11 @@ bool SensorDevice::isDirectReportSupported() const { return mIsDirectReportSupported; } -void SensorDevice::convertToSensorEvent( - const Event &src, sensors_event_t *dst) { +void SensorDevice::convertToSensorEvent(const Event& src, sensors_event_t* dst) { V2_1::implementation::convertToSensorEvent(src, dst); if (src.sensorType == V2_1::SensorType::DYNAMIC_SENSOR_META) { - const DynamicSensorInfo &dyn = src.u.dynamic; + const DynamicSensorInfo& dyn = src.u.dynamic; dst->dynamic_sensor_meta.connected = dyn.connected; dst->dynamic_sensor_meta.handle = dyn.sensorHandle; @@ -1184,10 +1168,9 @@ void SensorDevice::convertToSensorEvent( // marks it as oneway. auto it = mConnectedDynamicSensors.find(dyn.sensorHandle); if (it == mConnectedDynamicSensors.end()) { - mDynamicSensorsCv.wait_for(lock, MAX_DYN_SENSOR_WAIT, - [&, dyn]{ - return mConnectedDynamicSensors.find(dyn.sensorHandle) - != mConnectedDynamicSensors.end(); + mDynamicSensorsCv.wait_for(lock, MAX_DYN_SENSOR_WAIT, [&, dyn] { + return mConnectedDynamicSensors.find(dyn.sensorHandle) != + mConnectedDynamicSensors.end(); }); it = mConnectedDynamicSensors.find(dyn.sensorHandle); CHECK(it != mConnectedDynamicSensors.end()); @@ -1195,18 +1178,15 @@ void SensorDevice::convertToSensorEvent( dst->dynamic_sensor_meta.sensor = it->second; - memcpy(dst->dynamic_sensor_meta.uuid, - dyn.uuid.data(), + memcpy(dst->dynamic_sensor_meta.uuid, dyn.uuid.data(), sizeof(dst->dynamic_sensor_meta.uuid)); } } } -void SensorDevice::convertToSensorEventsAndQuantize( - const hidl_vec &src, - const hidl_vec &dynamicSensorsAdded, - sensors_event_t *dst) { - +void SensorDevice::convertToSensorEventsAndQuantize(const hidl_vec& src, + const hidl_vec& dynamicSensorsAdded, + sensors_event_t* dst) { if (dynamicSensorsAdded.size() > 0) { onDynamicSensorsConnected(dynamicSensorsAdded); } @@ -1214,26 +1194,27 @@ void SensorDevice::convertToSensorEventsAndQuantize( for (size_t i = 0; i < src.size(); ++i) { V2_1::implementation::convertToSensorEvent(src[i], &dst[i]); android::SensorDeviceUtils::quantizeSensorEventValues(&dst[i], - getResolutionForSensor(dst[i].sensor)); + getResolutionForSensor( + dst[i].sensor)); } } float SensorDevice::getResolutionForSensor(int sensorHandle) { for (size_t i = 0; i < mSensorList.size(); i++) { - if (sensorHandle == mSensorList[i].handle) { - return mSensorList[i].resolution; - } + if (sensorHandle == mSensorList[i].handle) { + return mSensorList[i].resolution; + } } auto it = mConnectedDynamicSensors.find(sensorHandle); if (it != mConnectedDynamicSensors.end()) { - return it->second->resolution; + return it->second->resolution; } return 0; } -void SensorDevice::handleHidlDeath(const std::string & detail) { +void SensorDevice::handleHidlDeath(const std::string& detail) { if (!mSensors->supportsMessageQueues()) { // restart is the only option at present. LOG_ALWAYS_FATAL("Abort due to ISensors hidl service failure, detail: %s.", detail.c_str()); diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h index e90a02ff2e..2f24e5fd0d 100644 --- a/services/sensorservice/SensorDevice.h +++ b/services/sensorservice/SensorDevice.h @@ -17,14 +17,14 @@ #ifndef ANDROID_SENSOR_DEVICE_H #define ANDROID_SENSOR_DEVICE_H +#include "ISensorsWrapper.h" #include "SensorDeviceUtils.h" #include "SensorService.h" #include "SensorServiceUtils.h" -#include "ISensorsWrapper.h" #include -#include #include +#include #include #include #include @@ -33,8 +33,8 @@ #include #include //std::max std::min -#include #include +#include #include #include "RingBuffer.h" @@ -49,12 +49,10 @@ class SensorsHalDeathReceivier : public android::hardware::hidl_death_recipient const wp<::android::hidl::base::V1_0::IBase>& service) override; }; -class SensorDevice : public Singleton, - public SensorServiceUtil::Dumpable { +class SensorDevice : public Singleton, public SensorServiceUtil::Dumpable { public: class HidlTransportErrorLog { - public: - + public: HidlTransportErrorLog() { mTs = 0; mCount = 0; @@ -67,7 +65,7 @@ public: String8 toString() const { String8 result; - struct tm *timeInfo = localtime(&mTs); + struct tm* timeInfo = localtime(&mTs); result.appendFormat("%02d:%02d:%02d :: %d", timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec, mCount); return result; @@ -75,7 +73,7 @@ public: private: time_t mTs; // timestamp of the error - int mCount; // number of transport errors observed + int mCount; // number of transport errors observed }; ~SensorDevice(); @@ -100,29 +98,27 @@ public: status_t setMode(uint32_t mode); bool isDirectReportSupported() const; - int32_t registerDirectChannel(const sensors_direct_mem_t *memory); + int32_t registerDirectChannel(const sensors_direct_mem_t* memory); void unregisterDirectChannel(int32_t channelHandle); - int32_t configureDirectChannel(int32_t sensorHandle, - int32_t channelHandle, const struct sensors_direct_cfg_t *config); + int32_t configureDirectChannel(int32_t sensorHandle, int32_t channelHandle, + const struct sensors_direct_cfg_t* config); void disableAllSensors(); void enableAllSensors(); - void autoDisable(void *ident, int handle); + void autoDisable(void* ident, int handle); - status_t injectSensorData(const sensors_event_t *event); - void notifyConnectionDestroyed(void *ident); + status_t injectSensorData(const sensors_event_t* event); + void notifyConnectionDestroyed(void* ident); using Result = ::android::hardware::sensors::V1_0::Result; hardware::Return onDynamicSensorsConnected( - const hardware::hidl_vec &dynamicSensorsAdded); + const hardware::hidl_vec& dynamicSensorsAdded); hardware::Return onDynamicSensorsDisconnected( - const hardware::hidl_vec &dynamicSensorHandlesRemoved); + const hardware::hidl_vec& dynamicSensorHandlesRemoved); void setUidStateForConnection(void* ident, SensorService::UidState state); - bool isReconnecting() const { - return mReconnecting; - } + bool isReconnecting() const { return mReconnecting; } bool isSensorActive(int handle) const; @@ -133,6 +129,7 @@ public: // Dumpable virtual std::string dump() const override; virtual void dump(util::ProtoOutputStream* proto) const override; + private: friend class Singleton; @@ -148,26 +145,26 @@ private: std::condition_variable mDynamicSensorsCv; static constexpr std::chrono::seconds MAX_DYN_SENSOR_WAIT{5}; - static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz - mutable Mutex mLock; // protect mActivationCount[].batchParams + static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz + mutable Mutex mLock; // protect mActivationCount[].batchParams // fixed-size array after construction // Struct to store all the parameters(samplingPeriod, maxBatchReportLatency and flags) from // batch call. For continous mode clients, maxBatchReportLatency is set to zero. struct BatchParams { - nsecs_t mTSample, mTBatch; - BatchParams() : mTSample(INT64_MAX), mTBatch(INT64_MAX) {} - BatchParams(nsecs_t tSample, nsecs_t tBatch): mTSample(tSample), mTBatch(tBatch) {} - bool operator != (const BatchParams& other) { - return !(mTSample == other.mTSample && mTBatch == other.mTBatch); - } - // Merge another parameter with this one. The updated mTSample will be the min of the two. - // The update mTBatch will be the min of original mTBatch and the apparent batch period - // of the other. the apparent batch is the maximum of mTBatch and mTSample, - void merge(const BatchParams &other) { - mTSample = std::min(mTSample, other.mTSample); - mTBatch = std::min(mTBatch, std::max(other.mTBatch, other.mTSample)); - } + nsecs_t mTSample, mTBatch; + BatchParams() : mTSample(INT64_MAX), mTBatch(INT64_MAX) {} + BatchParams(nsecs_t tSample, nsecs_t tBatch) : mTSample(tSample), mTBatch(tBatch) {} + bool operator!=(const BatchParams& other) { + return !(mTSample == other.mTSample && mTBatch == other.mTBatch); + } + // Merge another parameter with this one. The updated mTSample will be the min of the two. + // The update mTBatch will be the min of original mTBatch and the apparent batch period + // of the other. the apparent batch is the maximum of mTBatch and mTSample, + void merge(const BatchParams& other) { + mTSample = std::min(mTSample, other.mTSample); + mTBatch = std::min(mTBatch, std::max(other.mTBatch, other.mTSample)); + } }; // Store batch parameters in the KeyedVector and the optimal batch_rate and timeout in @@ -225,7 +222,7 @@ private: static_assert(DisabledReason::DISABLED_REASON_MAX < sizeof(uint8_t) * CHAR_BIT); // Use this map to determine which client is activated or deactivated. - std::unordered_map mDisabledClients; + std::unordered_map mDisabledClients; void addDisabledReasonForIdentLocked(void* ident, DisabledReason reason); void removeDisabledReasonForIdentLocked(void* ident, DisabledReason reason); @@ -239,8 +236,8 @@ private: static bool sensorIsEquivalent(const sensor_t& prevSensor, const sensor_t& newSensor); enum HalConnectionStatus { - CONNECTED, // Successfully connected to the HAL - DOES_NOT_EXIST, // Could not find the HAL + CONNECTED, // Successfully connected to the HAL + DOES_NOT_EXIST, // Could not find the HAL FAILED_TO_CONNECT, // Found the HAL but failed to connect/initialize UNKNOWN, }; @@ -258,32 +255,31 @@ private: status_t updateBatchParamsLocked(int handle, Info& info); status_t doActivateHardwareLocked(int handle, bool enable); - void handleHidlDeath(const std::string &detail); - template + void handleHidlDeath(const std::string& detail); + template void checkReturn(const Return& ret) { if (!ret.isOk()) { handleHidlDeath(ret.description()); } } status_t checkReturnAndGetStatus(const Return& ret); - //TODO(b/67425500): remove waiter after bug is resolved. + // TODO(b/67425500): remove waiter after bug is resolved. sp mRestartWaiter; bool isClientDisabled(void* ident) const; bool isClientDisabledLocked(void* ident) const; - std::vector getDisabledClientsLocked() const; + std::vector getDisabledClientsLocked() const; bool clientHasNoAccessLocked(void* ident) const; using Event = hardware::sensors::V2_1::Event; using SensorInfo = hardware::sensors::V2_1::SensorInfo; - void convertToSensorEvent(const Event &src, sensors_event_t *dst); + void convertToSensorEvent(const Event& src, sensors_event_t* dst); - void convertToSensorEventsAndQuantize( - const hardware::hidl_vec &src, - const hardware::hidl_vec &dynamicSensorsAdded, - sensors_event_t *dst); + void convertToSensorEventsAndQuantize(const hardware::hidl_vec& src, + const hardware::hidl_vec& dynamicSensorsAdded, + sensors_event_t* dst); float getResolutionForSensor(int sensorHandle); -- cgit v1.2.3-59-g8ed1b From ad741ccb93731e1fcfb307de1491eede00d096eb Mon Sep 17 00:00:00 2001 From: "Yao, Kefei" Date: Mon, 1 Nov 2021 15:20:31 +0800 Subject: Treat fence with error as invalid in terms of signal time Previously, fence with error was treated as pending, resulting in buffer not being able to be latched. This is especially bad when GPU hang happened and driver has restored context and states being able to recover the pipeline, but the whole pipeline is stuck at the buffer consumer (surfaceflinger) failing to consume the buffer, essentially because of fence error. Treating fence error as signaled but fence time as invalid, eliminate the possiblity of such defect while still sounding the alarm to the rest of the system regarding signal time of the underlying fence Also this could be justified by kernel, the status of a dma_fence is defined as 0 if the fence has not yet been signaled, 1 if the fence has been signaled without an error condition, or a negtive error code if the fence has been completed in err (see dma-fence.h). In this sense, a fence with error should not be treated as *not* signaled either. Bug: 204919015 Test: Manually trigger a GPU hang, the layer undergoing the GPU hang recovered from the hang and continuously get rendered as apposed to freezing Change-Id: Idc8e85f132520576802d1ebc32b2597bfe341be0 --- libs/ui/Fence.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp index 33ab7c470e..cc96f83578 100644 --- a/libs/ui/Fence.cpp +++ b/libs/ui/Fence.cpp @@ -132,9 +132,13 @@ nsecs_t Fence::getSignalTime() const { ALOGE("sync_file_info returned NULL for fd %d", mFenceFd.get()); return SIGNAL_TIME_INVALID; } + if (finfo->status != 1) { + const auto status = finfo->status; + ALOGE_IF(status < 0, "%s: sync_file_info contains an error: <%d> for fd: <%d>", __func__, + status, mFenceFd.get()); sync_file_info_free(finfo); - return SIGNAL_TIME_PENDING; + return status < 0 ? SIGNAL_TIME_INVALID : SIGNAL_TIME_PENDING; } uint64_t timestamp = 0; -- cgit v1.2.3-59-g8ed1b From 957706030117d1dabdf57ee794c23f1df77089f6 Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Mon, 15 Nov 2021 11:16:26 -0800 Subject: Add BT2020 HLG and variant into ADataSpace Bug: 201535612 Test: build pass Change-Id: Iecde54a4ba554f16bcb381ab65c8d9d8f22222bb --- libs/nativewindow/ANativeWindow.cpp | 4 ++++ libs/nativewindow/include/android/data_space.h | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 93e7239783..988d2a0876 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -170,6 +170,10 @@ int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpa static_assert(static_cast(ADATASPACE_BT709) == static_cast(HAL_DATASPACE_V0_BT709)); static_assert(static_cast(ADATASPACE_DCI_P3) == static_cast(HAL_DATASPACE_DCI_P3)); static_assert(static_cast(ADATASPACE_SRGB_LINEAR) == static_cast(HAL_DATASPACE_V0_SRGB_LINEAR)); + static_assert(static_cast(ADATASPACE_BT2020_HLG) == + static_cast(HAL_DATASPACE_BT2020_HLG)); + static_assert(static_cast(ADATASPACE_BT2020_ITU_HLG) == + static_cast(HAL_DATASPACE_BT2020_ITU_HLG)); if (!window || !query(window, NATIVE_WINDOW_IS_VALID) || !isDataSpaceValid(window, dataSpace)) { diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h index 0565f424f2..bc4a91409c 100644 --- a/libs/nativewindow/include/android/data_space.h +++ b/libs/nativewindow/include/android/data_space.h @@ -519,6 +519,20 @@ enum ADataSpace { * components. */ ADATASPACE_SRGB_LINEAR = 138477568, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL + + /** + * Hybrid Log Gamma encoding: + * + * Use full range, hybrid log gamma transfer and BT2020 standard. + */ + ADATASPACE_BT2020_HLG = 168165376, // STANDARD_BT2020 | TRANSFER_HLG | RANGE_FULL + + /** + * ITU Hybrid Log Gamma encoding: + * + * Use limited range, hybrid log gamma transfer and BT2020 standard. + */ + ADATASPACE_BT2020_ITU_HLG = 302383104 // STANDARD_BT2020 | TRANSFER_HLG | RANGE_LIMITED }; __END_DECLS -- cgit v1.2.3-59-g8ed1b From d948957b396a9301e6e247023d8509f44f6cf87c Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 12 Nov 2021 20:08:38 -0800 Subject: Look up source using & instead of equality Source for an input device may be composite. On some devices, the source is specified as TOUCHSCREEN | STYLUS. That means a regular lookup of a MotionRange using just SOURCE_TOUCHSCREEN fails. Update the code to allow composite sources. Also, improve the source dump by printing words instead of numbers. Bug: 198472780 Test: adb shell dumpsys input Change-Id: I8d395f2bb5a6db031e5c2aa6c1f5152ff067a2bb --- include/input/Input.h | 4 ++ libs/input/Input.cpp | 47 ++++++++++++++++++++-- libs/input/InputDevice.cpp | 6 +-- services/inputflinger/InputClassifier.cpp | 3 +- services/inputflinger/dispatcher/Entry.cpp | 20 ++++----- .../inputflinger/dispatcher/InputDispatcher.cpp | 4 -- 6 files changed, 62 insertions(+), 22 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index 7cc595a264..263ade40fb 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -203,6 +203,10 @@ class Parcel; const char* inputEventTypeToString(int32_t type); +std::string inputEventSourceToString(int32_t source); + +bool isFromSource(uint32_t source, uint32_t test); + /* * Flags that flow alongside events in the input dispatch system to help with certain * policy decisions such as waking from device sleep. diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 24a77209c4..a1d75d5fb1 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -66,10 +66,6 @@ vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) return transformedXy - transformedOrigin; } -bool isFromSource(uint32_t source, uint32_t test) { - return (source & test) == test; -} - bool shouldDisregardTransformation(uint32_t source) { // Do not apply any transformations to axes from joysticks or touchpads. return isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK) || @@ -148,6 +144,49 @@ const char* inputEventTypeToString(int32_t type) { return "UNKNOWN"; } +std::string inputEventSourceToString(int32_t source) { + if (source == AINPUT_SOURCE_UNKNOWN) { + return "UNKNOWN"; + } + if (source == static_cast(AINPUT_SOURCE_ANY)) { + return "ANY"; + } + static const std::map SOURCES{ + {AINPUT_SOURCE_KEYBOARD, "KEYBOARD"}, + {AINPUT_SOURCE_DPAD, "DPAD"}, + {AINPUT_SOURCE_GAMEPAD, "GAMEPAD"}, + {AINPUT_SOURCE_TOUCHSCREEN, "TOUCHSCREEN"}, + {AINPUT_SOURCE_MOUSE, "MOUSE"}, + {AINPUT_SOURCE_STYLUS, "STYLUS"}, + {AINPUT_SOURCE_BLUETOOTH_STYLUS, "BLUETOOTH_STYLUS"}, + {AINPUT_SOURCE_TRACKBALL, "TRACKBALL"}, + {AINPUT_SOURCE_MOUSE_RELATIVE, "MOUSE_RELATIVE"}, + {AINPUT_SOURCE_TOUCHPAD, "TOUCHPAD"}, + {AINPUT_SOURCE_TOUCH_NAVIGATION, "TOUCH_NAVIGATION"}, + {AINPUT_SOURCE_JOYSTICK, "JOYSTICK"}, + {AINPUT_SOURCE_HDMI, "HDMI"}, + {AINPUT_SOURCE_SENSOR, "SENSOR"}, + {AINPUT_SOURCE_ROTARY_ENCODER, "ROTARY_ENCODER"}, + }; + std::string result; + for (const auto& [source_entry, str] : SOURCES) { + if ((source & source_entry) == source_entry) { + if (!result.empty()) { + result += " | "; + } + result += str; + } + } + if (result.empty()) { + result = StringPrintf("0x%08x", source); + } + return result; +} + +bool isFromSource(uint32_t source, uint32_t test) { + return (source & test) == test; +} + VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event) { return {{VerifiedInputEvent::Type::KEY, event.getDeviceId(), event.getEventTime(), event.getSource(), event.getDisplayId()}, diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp index 015bd81361..ac84627b3f 100644 --- a/libs/input/InputDevice.cpp +++ b/libs/input/InputDevice.cpp @@ -208,10 +208,8 @@ void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t control const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange( int32_t axis, uint32_t source) const { - size_t numRanges = mMotionRanges.size(); - for (size_t i = 0; i < numRanges; i++) { - const MotionRange& range = mMotionRanges[i]; - if (range.axis == axis && range.source == source) { + for (const MotionRange& range : mMotionRanges) { + if (range.axis == axis && isFromSource(range.source, source)) { return ⦥ } } diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index 29d8a0f441..19cad7b9ad 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -68,7 +68,8 @@ static MotionClassification getMotionClassification(common::V1_0::Classification } static bool isTouchEvent(const NotifyMotionArgs& args) { - return args.source == AINPUT_SOURCE_TOUCHPAD || args.source == AINPUT_SOURCE_TOUCHSCREEN; + return isFromSource(args.source, AINPUT_SOURCE_TOUCHPAD) || + isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN); } // --- ClassifierEvent --- diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index c03581d8da..1674afd02e 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -175,13 +175,13 @@ std::string KeyEntry::getDescription() const { if (!GetBoolProperty("ro.debuggable", false)) { return "KeyEvent"; } - return StringPrintf("KeyEvent(deviceId=%d, eventTime=%" PRIu64 - ", source=0x%08x, displayId=%" PRId32 ", action=%s, " + return StringPrintf("KeyEvent(deviceId=%d, eventTime=%" PRIu64 ", source=%s, displayId=%" PRId32 + ", action=%s, " "flags=0x%08x, keyCode=%s(%d), scanCode=%d, metaState=0x%08x, " "repeatCount=%d), policyFlags=0x%08x", - deviceId, eventTime, source, displayId, KeyEvent::actionToString(action), - flags, KeyEvent::getLabel(keyCode), keyCode, scanCode, metaState, - repeatCount, policyFlags); + deviceId, eventTime, inputEventSourceToString(source).c_str(), displayId, + KeyEvent::actionToString(action), flags, KeyEvent::getLabel(keyCode), + keyCode, scanCode, metaState, repeatCount, policyFlags); } void KeyEntry::recycle() { @@ -249,12 +249,12 @@ std::string MotionEntry::getDescription() const { } std::string msg; msg += StringPrintf("MotionEvent(deviceId=%d, eventTime=%" PRIu64 - ", source=0x%08x, displayId=%" PRId32 + ", source=%s, displayId=%" PRId32 ", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, " "buttonState=0x%08x, " "classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, " "xCursorPosition=%0.1f, yCursorPosition=%0.1f, pointers=[", - deviceId, eventTime, source, displayId, + deviceId, eventTime, inputEventSourceToString(source).c_str(), displayId, MotionEvent::actionToString(action).c_str(), actionButton, flags, metaState, buttonState, motionClassificationToString(classification), edgeFlags, xPrecision, yPrecision, xCursorPosition, yCursorPosition); @@ -289,9 +289,11 @@ SensorEntry::~SensorEntry() {} std::string SensorEntry::getDescription() const { std::string msg; - msg += StringPrintf("SensorEntry(deviceId=%d, source=0x%08x, sensorType=0x%08x, " + std::string sensorTypeStr(ftl::enum_name(sensorType).value_or("?")); + msg += StringPrintf("SensorEntry(deviceId=%d, source=%s, sensorType=%s, " "accuracy=0x%08x, hwTimestamp=%" PRId64, - deviceId, source, sensorType, accuracy, hwTimestamp); + deviceId, inputEventSourceToString(source).c_str(), sensorTypeStr.c_str(), + accuracy, hwTimestamp); if (!GetBoolProperty("ro.debuggable", false)) { for (size_t i = 0; i < values.size(); i++) { diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 1b19311b2f..44409a262e 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -516,10 +516,6 @@ bool isConnectionResponsive(const Connection& connection) { return true; } -bool isFromSource(uint32_t source, uint32_t test) { - return (source & test) == test; -} - vec2 transformWithoutTranslation(const ui::Transform& transform, float x, float y) { const vec2 transformedXy = transform.transform(x, y); const vec2 transformedOrigin = transform.transform(0, 0); -- cgit v1.2.3-59-g8ed1b From 8b4ab814aed06a4afc22831390e0739c59f811ed Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Thu, 11 Nov 2021 12:37:30 -0800 Subject: Only scale SDR luminance by content max luminance for tonemapping If color conversion is SDR->SDR, then scale luminance only by the display luminance. The use-case is for applying a color transform, which was defined to occcur in linear space. Since uniform generation for tonemapping is (for now) dataspace-agnostic, this means that scaling by the content luminance should not be used since a tone-mapping operator may override the one that is provided by applications. Bug: 200310159 Test: builds, boots Test: librenderengine_test Change-Id: I2cc5860b6df064664c5e462674df20b589eae291 --- libs/renderengine/skia/filters/LinearEffect.cpp | 31 ++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp index 53136e40b7..c3a5a60e13 100644 --- a/libs/renderengine/skia/filters/LinearEffect.cpp +++ b/libs/renderengine/skia/filters/LinearEffect.cpp @@ -114,7 +114,8 @@ static void generateXYZTransforms(SkString& shader) { } // Conversion from relative light to absolute light (maps from [0, 1] to [0, maxNits]) -static void generateLuminanceScalesForOOTF(ui::Dataspace inputDataspace, SkString& shader) { +static void generateLuminanceScalesForOOTF(ui::Dataspace inputDataspace, + ui::Dataspace outputDataspace, SkString& shader) { switch (inputDataspace & HAL_DATASPACE_TRANSFER_MASK) { case HAL_DATASPACE_TRANSFER_ST2084: shader.append(R"( @@ -131,12 +132,26 @@ static void generateLuminanceScalesForOOTF(ui::Dataspace inputDataspace, SkStrin )"); break; default: - shader.append(R"( - float3 ScaleLuminance(float3 xyz) { - return xyz * in_libtonemap_inputMaxLuminance; - } - )"); - break; + switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) { + case HAL_DATASPACE_TRANSFER_ST2084: + case HAL_DATASPACE_TRANSFER_HLG: + // SDR -> HDR tonemap + shader.append(R"( + float3 ScaleLuminance(float3 xyz) { + return xyz * in_libtonemap_inputMaxLuminance; + } + )"); + break; + default: + // Input and output are both SDR, so no tone-mapping is expected so + // no-op the luminance normalization. + shader.append(R"( + float3 ScaleLuminance(float3 xyz) { + return xyz * in_libtonemap_displayMaxLuminance; + } + )"); + break; + } } } @@ -174,7 +189,7 @@ static void generateOOTF(ui::Dataspace inputDataspace, ui::Dataspace outputDatas toAidlDataspace(outputDataspace)) .c_str()); - generateLuminanceScalesForOOTF(inputDataspace, shader); + generateLuminanceScalesForOOTF(inputDataspace, outputDataspace, shader); generateLuminanceNormalizationForOOTF(outputDataspace, shader); shader.append(R"( -- cgit v1.2.3-59-g8ed1b From 5184f413900601d737488eaf9c53dcfe8ae39d16 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Thu, 14 Oct 2021 18:13:49 -0700 Subject: Add experimental tonemapper for Android 13 This has the following purposes: 1. Demonstrates the ability of libtonemap to swap out tonemapping curves without invasive changes into dependent systems such as RenderEngine. Notably, the only production code modified in this patch was tonemap.cpp. 2. Assume a reasonable max content luminance. Some content may fail to set a reasonable luminance level as part of their HDR10 metadata. 3. Track greylevels as piecewise linear interpolations, rather than piecewise hermitians. This has the effect of smoothly converging to max display luminance which can reduce banding effects in highights. Bug: 200310159 Test: libtonemap_test Test: HDR youtube Change-Id: I08990aa402d6e503885e81397041f22957232079 --- libs/tonemap/tonemap.cpp | 158 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 156 insertions(+), 2 deletions(-) diff --git a/libs/tonemap/tonemap.cpp b/libs/tonemap/tonemap.cpp index 350bca427c..2cec773eb3 100644 --- a/libs/tonemap/tonemap.cpp +++ b/libs/tonemap/tonemap.cpp @@ -26,10 +26,11 @@ namespace { // Flag containing the variant of tone map algorithm to use. enum class ToneMapAlgorithm { - AndroidO, // Default algorithm in place since Android O, + AndroidO, // Default algorithm in place since Android O, + Android13, // Algorithm used in Android 13. }; -static const constexpr auto kToneMapAlgorithm = ToneMapAlgorithm::AndroidO; +static const constexpr auto kToneMapAlgorithm = ToneMapAlgorithm::Android13; static const constexpr auto kTransferMask = static_cast(aidl::android::hardware::graphics::common::Dataspace::TRANSFER_MASK); @@ -231,7 +232,158 @@ public: .value = buildUniformValue(metadata.displayMaxLuminance)}); uniforms.push_back({.name = "in_libtonemap_inputMaxLuminance", .value = buildUniformValue(metadata.contentMaxLuminance)}); + return uniforms; + } +}; + +class ToneMapper13 : public ToneMapper { +public: + std::string generateTonemapGainShaderSkSL( + aidl::android::hardware::graphics::common::Dataspace sourceDataspace, + aidl::android::hardware::graphics::common::Dataspace destinationDataspace) override { + const int32_t sourceDataspaceInt = static_cast(sourceDataspace); + const int32_t destinationDataspaceInt = static_cast(destinationDataspace); + + std::string program; + // Input uniforms + program.append(R"( + uniform float in_libtonemap_displayMaxLuminance; + uniform float in_libtonemap_inputMaxLuminance; + )"); + switch (sourceDataspaceInt & kTransferMask) { + case kTransferST2084: + case kTransferHLG: + switch (destinationDataspaceInt & kTransferMask) { + case kTransferST2084: + program.append(R"( + float libtonemap_ToneMapTargetNits(float maxRGB) { + return maxRGB; + } + )"); + break; + case kTransferHLG: + // PQ has a wider luminance range (10,000 nits vs. 1,000 nits) than HLG, so + // we'll clamp the luminance range in case we're mapping from PQ input to + // HLG output. + program.append(R"( + float libtonemap_ToneMapTargetNits(float maxRGB) { + return clamp(maxRGB, 0.0, 1000.0); + } + )"); + break; + + default: + switch (sourceDataspaceInt & kTransferMask) { + case kTransferST2084: + program.append(R"( + float libtonemap_OETFTone(float channel) { + channel = channel / 10000.0; + float m1 = (2610.0 / 4096.0) / 4.0; + float m2 = (2523.0 / 4096.0) * 128.0; + float c1 = (3424.0 / 4096.0); + float c2 = (2413.0 / 4096.0) * 32.0; + float c3 = (2392.0 / 4096.0) * 32.0; + + float tmp = pow(channel, float(m1)); + tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp); + return pow(tmp, float(m2)); + } + )"); + break; + case kTransferHLG: + program.append(R"( + float libtonemap_OETFTone(float channel) { + channel = channel / 1000.0; + const float a = 0.17883277; + const float b = 0.28466892; + const float c = 0.55991073; + return channel <= 1.0 / 12.0 ? sqrt(3.0 * channel) : + a * log(12.0 * channel - b) + c; + } + )"); + break; + } + // Here we're mapping from HDR to SDR content, so interpolate using a + // Hermitian polynomial onto the smaller luminance range. + program.append(R"( + float libtonemap_ToneMapTargetNits(float maxRGB) { + float maxInLumi = in_libtonemap_inputMaxLuminance; + float maxOutLumi = in_libtonemap_displayMaxLuminance; + + float nits = maxRGB; + + float x1 = maxOutLumi * 0.65; + float y1 = x1; + + float x3 = maxInLumi; + float y3 = maxOutLumi; + + float x2 = x1 + (x3 - x1) * 4.0 / 17.0; + float y2 = maxOutLumi * 0.9; + + float greyNorm1 = libtonemap_OETFTone(x1); + float greyNorm2 = libtonemap_OETFTone(x2); + float greyNorm3 = libtonemap_OETFTone(x3); + + float slope1 = 0; + float slope2 = (y2 - y1) / (greyNorm2 - greyNorm1); + float slope3 = (y3 - y2 ) / (greyNorm3 - greyNorm2); + + if (nits < x1) { + return nits; + } + + if (nits > maxInLumi) { + return maxOutLumi; + } + + float greyNits = libtonemap_OETFTone(nits); + + if (greyNits <= greyNorm2) { + nits = (greyNits - greyNorm2) * slope2 + y2; + } else if (greyNits <= greyNorm3) { + nits = (greyNits - greyNorm3) * slope3 + y3; + } else { + nits = maxOutLumi; + } + return nits; + } + )"); + break; + } + break; + default: + // Inverse tone-mapping and SDR-SDR mapping is not supported. + program.append(R"( + float libtonemap_ToneMapTargetNits(float maxRGB) { + return maxRGB; + } + )"); + break; + } + + program.append(R"( + float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz) { + float maxRGB = max(linearRGB.r, max(linearRGB.g, linearRGB.b)); + if (maxRGB <= 0.0) { + return 1.0; + } + return libtonemap_ToneMapTargetNits(maxRGB) / maxRGB; + } + )"); + return program; + } + + std::vector generateShaderSkSLUniforms(const Metadata& metadata) override { + // Hardcode the max content luminance to a "reasonable" level + static const constexpr float kContentMaxLuminance = 4000.f; + std::vector uniforms; + uniforms.reserve(2); + uniforms.push_back({.name = "in_libtonemap_displayMaxLuminance", + .value = buildUniformValue(metadata.displayMaxLuminance)}); + uniforms.push_back({.name = "in_libtonemap_inputMaxLuminance", + .value = buildUniformValue(kContentMaxLuminance)}); return uniforms; } }; @@ -247,6 +399,8 @@ ToneMapper* getToneMapper() { case ToneMapAlgorithm::AndroidO: sToneMapper = std::unique_ptr(new ToneMapperO()); break; + case ToneMapAlgorithm::Android13: + sToneMapper = std::unique_ptr(new ToneMapper13()); } }); -- cgit v1.2.3-59-g8ed1b From 71e78ac57093490f6f54df10b8d4885f0092f1c4 Mon Sep 17 00:00:00 2001 From: Arthur Ishiguro Date: Sun, 14 Nov 2021 01:18:47 +0000 Subject: Refactor dynamic sensor callback in SensorDevice - Isolates HIDL-specific code from SensorDevice methods. - Also avoids use of new/delete in internal storage. Bug: 195593357 Test: Run CTS Change-Id: If4e34509bfc047f5c22ef22e6c47c429ecbe894c --- services/sensorservice/SensorDevice.cpp | 54 ++++++++++++++++----------------- services/sensorservice/SensorDevice.h | 13 ++++---- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp index b118d8f577..c67acbfbcd 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -45,6 +45,7 @@ using android::hardware::sensors::V2_1::ISensorsCallback; using android::hardware::sensors::V2_1::implementation::convertToNewEvents; using android::hardware::sensors::V2_1::implementation::convertToNewSensorInfos; using android::hardware::sensors::V2_1::implementation::convertToOldSensorInfo; +using android::hardware::sensors::V2_1::implementation::convertToSensor; using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV1_0; using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV2_0; using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV2_1; @@ -98,19 +99,26 @@ struct SensorsCallback : public ISensorsCallback { Return onDynamicSensorsConnected_2_1( const hidl_vec& dynamicSensorsAdded) override { - return SensorDevice::getInstance().onDynamicSensorsConnected(dynamicSensorsAdded); + std::vector sensors; + for (const V2_1::SensorInfo& info : dynamicSensorsAdded) { + sensor_t sensor; + convertToSensor(info, &sensor); + sensors.push_back(sensor); + } + + SensorDevice::getInstance().onDynamicSensorsConnected(sensors); + return Return(); } Return onDynamicSensorsConnected( const hidl_vec& dynamicSensorsAdded) override { - return SensorDevice::getInstance().onDynamicSensorsConnected( - convertToNewSensorInfos(dynamicSensorsAdded)); + return onDynamicSensorsConnected_2_1(convertToNewSensorInfos(dynamicSensorsAdded)); } Return onDynamicSensorsDisconnected( const hidl_vec& dynamicSensorHandlesRemoved) override { - return SensorDevice::getInstance().onDynamicSensorsDisconnected( - dynamicSensorHandlesRemoved); + SensorDevice::getInstance().onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved); + return Return(); } }; @@ -138,7 +146,7 @@ void SensorDevice::initializeSensorList() { Info model; for (size_t i = 0; i < count; i++) { sensor_t sensor; - convertToSensor(convertToOldSensorInfo(list[i]), &sensor); + convertToSensor(list[i], &sensor); if (sensor.type < static_cast(SensorType::DEVICE_PRIVATE_BASE)) { sensor.resolution = SensorDeviceUtils::resolutionForSensor(sensor); @@ -289,8 +297,9 @@ SensorDevice::HalConnectionStatus SensorDevice::initializeHidlServiceV2_X() { CHECK(mSensors != nullptr && mWakeLockQueue != nullptr && mEventQueueFlag != nullptr && mWakeLockQueueFlag != nullptr); - status_t status = checkReturnAndGetStatus( - mSensors->initialize(*mWakeLockQueue->getDesc(), new SensorsCallback())); + mCallback = new SensorsCallback(); + status_t status = + checkReturnAndGetStatus(mSensors->initialize(*mWakeLockQueue->getDesc(), mCallback)); if (status != NO_ERROR) { connectionStatus = HalConnectionStatus::FAILED_TO_CONNECT; @@ -609,34 +618,26 @@ ssize_t SensorDevice::pollFmq(sensors_event_t* buffer, size_t maxNumEventsToRead return eventsRead; } -Return SensorDevice::onDynamicSensorsConnected( - const hidl_vec& dynamicSensorsAdded) { +void SensorDevice::onDynamicSensorsConnected(const std::vector& dynamicSensorsAdded) { std::unique_lock lock(mDynamicSensorsMutex); // Allocate a sensor_t structure for each dynamic sensor added and insert // it into the dictionary of connected dynamic sensors keyed by handle. for (size_t i = 0; i < dynamicSensorsAdded.size(); ++i) { - const SensorInfo& info = dynamicSensorsAdded[i]; + const sensor_t& sensor = dynamicSensorsAdded[i]; - auto it = mConnectedDynamicSensors.find(info.sensorHandle); + auto it = mConnectedDynamicSensors.find(sensor.handle); CHECK(it == mConnectedDynamicSensors.end()); - sensor_t* sensor = new sensor_t(); - convertToSensor(convertToOldSensorInfo(info), sensor); - - mConnectedDynamicSensors.insert(std::make_pair(sensor->handle, sensor)); + mConnectedDynamicSensors.insert(std::make_pair(sensor.handle, sensor)); } mDynamicSensorsCv.notify_all(); - - return Return(); } -Return SensorDevice::onDynamicSensorsDisconnected( - const hidl_vec& dynamicSensorHandlesRemoved) { - (void)dynamicSensorHandlesRemoved; +void SensorDevice::onDynamicSensorsDisconnected( + const std::vector& /* dynamicSensorHandlesRemoved */) { // TODO: Currently dynamic sensors do not seem to be removed - return Return(); } void SensorDevice::writeWakeLockHandled(uint32_t count) { @@ -710,7 +711,6 @@ status_t SensorDevice::activateLocked(void* ident, int handle, int enabled) { // dictionary. auto it = mConnectedDynamicSensors.find(handle); if (it != mConnectedDynamicSensors.end()) { - delete it->second; mConnectedDynamicSensors.erase(it); } @@ -1176,7 +1176,7 @@ void SensorDevice::convertToSensorEvent(const Event& src, sensors_event_t* dst) CHECK(it != mConnectedDynamicSensors.end()); } - dst->dynamic_sensor_meta.sensor = it->second; + dst->dynamic_sensor_meta.sensor = &it->second; memcpy(dst->dynamic_sensor_meta.uuid, dyn.uuid.data(), sizeof(dst->dynamic_sensor_meta.uuid)); @@ -1187,8 +1187,8 @@ void SensorDevice::convertToSensorEvent(const Event& src, sensors_event_t* dst) void SensorDevice::convertToSensorEventsAndQuantize(const hidl_vec& src, const hidl_vec& dynamicSensorsAdded, sensors_event_t* dst) { - if (dynamicSensorsAdded.size() > 0) { - onDynamicSensorsConnected(dynamicSensorsAdded); + if (dynamicSensorsAdded.size() > 0 && mCallback != nullptr) { + mCallback->onDynamicSensorsConnected_2_1(dynamicSensorsAdded); } for (size_t i = 0; i < src.size(); ++i) { @@ -1208,7 +1208,7 @@ float SensorDevice::getResolutionForSensor(int sensorHandle) { auto it = mConnectedDynamicSensors.find(sensorHandle); if (it != mConnectedDynamicSensors.end()) { - return it->second->resolution; + return it->second.resolution; } return 0; diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h index 2f24e5fd0d..314ddb8758 100644 --- a/services/sensorservice/SensorDevice.h +++ b/services/sensorservice/SensorDevice.h @@ -43,6 +43,8 @@ namespace android { +using Result = ::android::hardware::sensors::V1_0::Result; + // --------------------------------------------------------------------------- class SensorsHalDeathReceivier : public android::hardware::hidl_death_recipient { virtual void serviceDied(uint64_t cookie, @@ -110,11 +112,8 @@ public: status_t injectSensorData(const sensors_event_t* event); void notifyConnectionDestroyed(void* ident); - using Result = ::android::hardware::sensors::V1_0::Result; - hardware::Return onDynamicSensorsConnected( - const hardware::hidl_vec& dynamicSensorsAdded); - hardware::Return onDynamicSensorsDisconnected( - const hardware::hidl_vec& dynamicSensorHandlesRemoved); + void onDynamicSensorsConnected(const std::vector& dynamicSensorsAdded); + void onDynamicSensorsDisconnected(const std::vector& dynamicSensorHandlesRemoved); void setUidStateForConnection(void* ident, SensorService::UidState state); @@ -134,8 +133,9 @@ private: friend class Singleton; sp<::android::hardware::sensors::V2_1::implementation::ISensorsWrapperBase> mSensors; + sp<::android::hardware::sensors::V2_1::ISensorsCallback> mCallback; std::vector mSensorList; - std::unordered_map mConnectedDynamicSensors; + std::unordered_map mConnectedDynamicSensors; // A bug in the Sensors HIDL spec which marks onDynamicSensorsConnected as oneway causes dynamic // meta events and onDynamicSensorsConnected to be received out of order. This mutex + CV are @@ -262,6 +262,7 @@ private: handleHidlDeath(ret.description()); } } + status_t checkReturnAndGetStatus(const Return& ret); // TODO(b/67425500): remove waiter after bug is resolved. sp mRestartWaiter; -- cgit v1.2.3-59-g8ed1b From d8a36dea9fbba46d674530198e2b4925231f53c6 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 16 Nov 2021 07:46:07 -0800 Subject: Use std::shared_mutex in debug_report Bug: b/143295577 Change-Id: Iee285c4a7ea42fc25b5463f79894d3cca58f17c1 --- vulkan/libvulkan/debug_report.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vulkan/libvulkan/debug_report.h b/vulkan/libvulkan/debug_report.h index e5b1587b4f..416c0bc2e1 100644 --- a/vulkan/libvulkan/debug_report.h +++ b/vulkan/libvulkan/debug_report.h @@ -78,8 +78,7 @@ class DebugReportCallbackList { VkDebugReportCallbackEXT driver_handle; }; - // TODO(b/143295577): use std::shared_mutex when available in libc++ - mutable std::shared_timed_mutex rwmutex_; + mutable std::shared_mutex rwmutex_; Node head_; }; -- cgit v1.2.3-59-g8ed1b From 931f4401963265a5f8b2b54b4a7d90ab090891e1 Mon Sep 17 00:00:00 2001 From: Arthur Ishiguro Date: Tue, 16 Nov 2021 00:32:46 +0000 Subject: Remove duplicate entry in PREUPLOAD.cfg Test: Upload Change-Id: I64dc19e7d266417c4e7d054466b78972e5bdf933 --- PREUPLOAD.cfg | 1 - 1 file changed, 1 deletion(-) diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 3b2a9e7dad..f0545960a7 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -1,7 +1,6 @@ [Builtin Hooks] bpfmt = true clang_format = true -bpfmt = true [Builtin Hooks Options] # Only turn on clang-format check for the following subfolders. -- cgit v1.2.3-59-g8ed1b From 31c3f57fdce7b73f3ad8f14be404b97299f23f6d Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Tue, 16 Nov 2021 10:14:50 -0800 Subject: Add BT2020 PQ variant to ADataSpace Bug: 201535612 Test: builds Change-Id: I0851a5fcf8afaa8cf9f9f8a6d15da3f60e601fd5 --- libs/nativewindow/ANativeWindow.cpp | 2 ++ libs/nativewindow/include/android/data_space.h | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 93e7239783..5823207517 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -162,6 +162,8 @@ int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpa static_assert(static_cast(ADATASPACE_SCRGB) == static_cast(HAL_DATASPACE_V0_SCRGB)); static_assert(static_cast(ADATASPACE_DISPLAY_P3) == static_cast(HAL_DATASPACE_DISPLAY_P3)); static_assert(static_cast(ADATASPACE_BT2020_PQ) == static_cast(HAL_DATASPACE_BT2020_PQ)); + static_assert(static_cast(ADATASPACE_BT2020_ITU_PQ) == + static_cast(HAL_DATASPACE_BT2020_ITU_PQ)); static_assert(static_cast(ADATASPACE_ADOBE_RGB) == static_cast(HAL_DATASPACE_ADOBE_RGB)); static_assert(static_cast(ADATASPACE_JFIF) == static_cast(HAL_DATASPACE_V0_JFIF)); static_assert(static_cast(ADATASPACE_BT601_625) == static_cast(HAL_DATASPACE_V0_BT601_625)); diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h index 0565f424f2..66f0e96873 100644 --- a/libs/nativewindow/include/android/data_space.h +++ b/libs/nativewindow/include/android/data_space.h @@ -443,6 +443,15 @@ enum ADataSpace { */ ADATASPACE_BT2020_PQ = 163971072, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_FULL + /** + * ITU-R Recommendation 2020 (BT.2020) + * + * Ultra High-definition television + * + * Use limited range, SMPTE 2084 (PQ) transfer and BT2020 standard + */ + ADATASPACE_BT2020_ITU_PQ = 298188800, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED + /** * Adobe RGB * -- cgit v1.2.3-59-g8ed1b From 5e3eaa86d6ab6853a1a7a17cc85d82e1f7362b67 Mon Sep 17 00:00:00 2001 From: Arthur Ishiguro Date: Thu, 11 Nov 2021 18:05:56 +0000 Subject: Create wrapper interface for SensorDevice Will be used to route invocations to HIDL/AIDL services. Bug: 195593357 Test: Compile Change-Id: I2a3a8e7d1fca4f80799d55fd72f20428701b0a68 --- services/sensorservice/ISensorHalWrapper.h | 81 ++++++++++++++++++++++++++ services/sensorservice/SensorService.h | 92 +++++++++++++++--------------- 2 files changed, 127 insertions(+), 46 deletions(-) create mode 100644 services/sensorservice/ISensorHalWrapper.h diff --git a/services/sensorservice/ISensorHalWrapper.h b/services/sensorservice/ISensorHalWrapper.h new file mode 100644 index 0000000000..c9e089e449 --- /dev/null +++ b/services/sensorservice/ISensorHalWrapper.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_ISENSOR_HAL_WRAPPER_H +#define ANDROID_ISENSOR_HAL_WRAPPER_H + +#include +#include +#include + +#include "SensorService.h" + +namespace android { + +/** + * A wrapper for various types of HAL implementation, e.g. to distinguish HIDL and AIDL versions. + */ +class ISensorHalWrapper { +public: + class ICallback : public ISensorsCallback { + + void onDynamicSensorsConnected( + const std::vector &dynamicSensorsAdded) = 0; + + void onDynamicSensorsDisconnected( + const std::vector &dynamicSensorHandlesRemoved) = 0; + }; + + /** + * Connects to the underlying sensors HAL. This should also be used for any reconnections + * due to HAL resets. + */ + virtual bool connect(ICallback *callback) = 0; + + /** + * Polls for available sensor events. This could be using the traditional sensors + * polling or from a FMQ. + */ + virtual ssize_t poll(sensors_event_t* buffer, size_t count) = 0; + + /** + * The below functions directly mirrors the sensors HAL definitions. + */ + virtual std::vector getSensorsList() = 0; + + virtual status_t setOperationMode(SensorService::Mode mode) = 0; + + virtual status_t activate(int32_t sensorHandle, bool enabled) = 0; + + virtual status_t batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) = 0; + + virtual status_t flush(int32_t sensorHandle) = 0; + + virtual status_t injectSensorData(const sensors_event_t *event) = 0; + + virtual status_t registerDirectChannel(const sensors_direct_mem_t *memory, + int32_t *channelHandle) = 0; + + virtual void unregisterDirectChannel(int32_t channelHandle) = 0; + + virtual status_t configureDirectChannel(int32_t sensorHandle, int32_t channelHandle, + const struct sensors_direct_cfg_t *config) = 0; +} + +} // namespace android + +#endif // ANDROID_ISENSOR_HAL_WRAPPER_H diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index b059e61130..9b6d01ab71 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -89,6 +89,52 @@ public: UID_STATE_IDLE, }; + enum Mode { + // The regular operating mode where any application can register/unregister/call flush on + // sensors. + NORMAL = 0, + // This mode is only used for testing purposes. Not all HALs support this mode. In this mode, + // the HAL ignores the sensor data provided by physical sensors and accepts the data that is + // injected from the SensorService as if it were the real sensor data. This mode is primarily + // used for testing various algorithms like vendor provided SensorFusion, Step Counter and + // Step Detector etc. Typically in this mode, there will be a client (a + // SensorEventConnection) which will be injecting sensor data into the HAL. Normal apps can + // unregister and register for any sensor that supports injection. Registering to sensors + // that do not support injection will give an error. TODO: Allow exactly one + // client to inject sensor data at a time. + DATA_INJECTION = 1, + // This mode is used only for testing sensors. Each sensor can be tested in isolation with + // the required sampling_rate and maxReportLatency parameters without having to think about + // the data rates requested by other applications. End user devices are always expected to be + // in NORMAL mode. When this mode is first activated, all active sensors from all connections + // are disabled. Calling flush() will return an error. In this mode, only the requests from + // selected apps whose package names are allowlisted are allowed (typically CTS apps). Only + // these apps can register/unregister/call flush() on sensors. If SensorService switches to + // NORMAL mode again, all sensors that were previously registered to are activated with the + // corresponding parameters if the application hasn't unregistered for sensors in the mean + // time. NOTE: Non allowlisted app whose sensors were previously deactivated may still + // receive events if a allowlisted app requests data from the same sensor. + RESTRICTED = 2 + + // State Transitions supported. + // RESTRICTED <--- NORMAL ---> DATA_INJECTION + // ---> <--- + + // Shell commands to switch modes in SensorService. + // 1) Put SensorService in RESTRICTED mode with packageName .cts. If it is already in + // restricted mode it is treated as a NO_OP (and packageName is NOT changed). + // + // $ adb shell dumpsys sensorservice restrict .cts. + // + // 2) Put SensorService in DATA_INJECTION mode with packageName .xts. If it is already in + // data_injection mode it is treated as a NO_OP (and packageName is NOT changed). + // + // $ adb shell dumpsys sensorservice data_injection .xts. + // + // 3) Reset sensorservice back to NORMAL mode. + // $ adb shell dumpsys sensorservice enable + }; + class ProximityActiveListener : public virtual RefBase { public: // Note that the callback is invoked from an async thread and can interact with the @@ -276,52 +322,6 @@ private: const int64_t mToken; }; - enum Mode { - // The regular operating mode where any application can register/unregister/call flush on - // sensors. - NORMAL = 0, - // This mode is only used for testing purposes. Not all HALs support this mode. In this mode, - // the HAL ignores the sensor data provided by physical sensors and accepts the data that is - // injected from the SensorService as if it were the real sensor data. This mode is primarily - // used for testing various algorithms like vendor provided SensorFusion, Step Counter and - // Step Detector etc. Typically in this mode, there will be a client (a - // SensorEventConnection) which will be injecting sensor data into the HAL. Normal apps can - // unregister and register for any sensor that supports injection. Registering to sensors - // that do not support injection will give an error. TODO(aakella) : Allow exactly one - // client to inject sensor data at a time. - DATA_INJECTION = 1, - // This mode is used only for testing sensors. Each sensor can be tested in isolation with - // the required sampling_rate and maxReportLatency parameters without having to think about - // the data rates requested by other applications. End user devices are always expected to be - // in NORMAL mode. When this mode is first activated, all active sensors from all connections - // are disabled. Calling flush() will return an error. In this mode, only the requests from - // selected apps whose package names are whitelisted are allowed (typically CTS apps). Only - // these apps can register/unregister/call flush() on sensors. If SensorService switches to - // NORMAL mode again, all sensors that were previously registered to are activated with the - // corresponding paramaters if the application hasn't unregistered for sensors in the mean - // time. NOTE: Non whitelisted app whose sensors were previously deactivated may still - // receive events if a whitelisted app requests data from the same sensor. - RESTRICTED = 2 - - // State Transitions supported. - // RESTRICTED <--- NORMAL ---> DATA_INJECTION - // ---> <--- - - // Shell commands to switch modes in SensorService. - // 1) Put SensorService in RESTRICTED mode with packageName .cts. If it is already in - // restricted mode it is treated as a NO_OP (and packageName is NOT changed). - // - // $ adb shell dumpsys sensorservice restrict .cts. - // - // 2) Put SensorService in DATA_INJECTION mode with packageName .xts. If it is already in - // data_injection mode it is treated as a NO_OP (and packageName is NOT changed). - // - // $ adb shell dumpsys sensorservice data_injection .xts. - // - // 3) Reset sensorservice back to NORMAL mode. - // $ adb shell dumpsys sensorservice enable - }; - static const char* WAKE_LOCK_NAME; virtual ~SensorService(); -- cgit v1.2.3-59-g8ed1b From 08c4fd4ecd0484e5993d6f34638224cc17c30244 Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Wed, 27 Oct 2021 19:06:56 -0700 Subject: Obsoleted VsyncEventData.expectedPresentTime. It was obsoleted after plumbing multiple frame timelines which each have expected present time. Bug: 198192508 Test: atest ChoreographerNativeTest Change-Id: Ib39f8093ff89c9f7831cc40375d7a0a5ae9408dc --- libs/gui/DisplayEventDispatcher.cpp | 1 - libs/gui/include/gui/DisplayEventDispatcher.h | 3 --- 2 files changed, 4 deletions(-) diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp index c986b82fd8..420246a064 100644 --- a/libs/gui/DisplayEventDispatcher.cpp +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -166,7 +166,6 @@ bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, outVsyncEventData->id = ev.vsync.vsyncId; outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp; outVsyncEventData->frameInterval = ev.vsync.frameInterval; - outVsyncEventData->expectedPresentTime = ev.vsync.expectedVSyncTimestamp; outVsyncEventData->preferredFrameTimelineIndex = ev.vsync.preferredFrameTimelineIndex; populateFrameTimelines(ev, outVsyncEventData); diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h index 92c89b8bde..db1b875982 100644 --- a/libs/gui/include/gui/DisplayEventDispatcher.h +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -35,9 +35,6 @@ struct VsyncEventData { // The current frame interval in ns when this frame was scheduled. int64_t frameInterval = 0; - // The anticipated Vsync present time. - int64_t expectedPresentTime = 0; - struct FrameTimeline { // The Vsync Id corresponsing to this vsync event. This will be used to // populate ISurfaceComposer::setFrameTimelineVsync and -- cgit v1.2.3-59-g8ed1b From 6b430413d07b6afca1a4146ea91809567b5cfe9a Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 4 Nov 2021 16:51:29 -0700 Subject: Change PointerController to display space PointerController used to work in the logical display space, so TouchInputMapper and CursorInputMapper would need to transform the coordinates before interacting with it. This CL makes PointerController work in the display space. It will transform incoming and outgoing coordinates to stay in the display space using the DisplayInfo provided by SurfaceFlinger. Using info provided by SF also means that there will be better synchonization between the pointers and display changes like rotation. Bug: 188939842 Bug: 144544464 Test: manual: ensure mouse and touch spots work in different display orientations and sizes set using "adb shell wm size" Change-Id: I764c070adef7e9f26c0062f1b3466c7115a305ac --- include/input/Input.h | 5 + libs/input/Input.cpp | 12 +-- .../include/PointerControllerInterface.h | 3 +- .../reader/mapper/CursorInputMapper.cpp | 17 +--- .../inputflinger/reader/mapper/CursorInputMapper.h | 2 - .../reader/mapper/TouchCursorInputMapperCommon.h | 20 ---- .../reader/mapper/TouchInputMapper.cpp | 110 +++++++-------------- .../inputflinger/reader/mapper/TouchInputMapper.h | 8 -- 8 files changed, 47 insertions(+), 130 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index 1e06257591..5242dcb476 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -201,6 +201,11 @@ namespace android { class Parcel; #endif +/* + * Apply the given transform to the point without applying any translation/offset. + */ +vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy); + const char* inputEventTypeToString(int32_t type); std::string inputEventSourceToString(int32_t source); diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 8974b22c86..cb93c92310 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -60,12 +60,6 @@ float transformAngle(const ui::Transform& transform, float angleRadians) { return atan2f(transformedPoint.x, -transformedPoint.y); } -vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) { - const vec2 transformedXy = transform.transform(xy); - const vec2 transformedOrigin = transform.transform(0, 0); - return transformedXy - transformedOrigin; -} - bool shouldDisregardTransformation(uint32_t source) { // Do not apply any transformations to axes from joysticks or touchpads. return isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK) || @@ -120,6 +114,12 @@ int32_t IdGenerator::nextId() const { // --- InputEvent --- +vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) { + const vec2 transformedXy = transform.transform(xy); + const vec2 transformedOrigin = transform.transform(0, 0); + return transformedXy - transformedOrigin; +} + const char* inputEventTypeToString(int32_t type) { switch (type) { case AINPUT_EVENT_TYPE_KEY: { diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h index b1069497d3..db4228d862 100644 --- a/services/inputflinger/include/PointerControllerInterface.h +++ b/services/inputflinger/include/PointerControllerInterface.h @@ -30,7 +30,8 @@ namespace android { * fingers * * The pointer controller is responsible for providing synchronization and for tracking - * display orientation changes if needed. + * display orientation changes if needed. It works in the display panel's coordinate space, which + * is the same coordinate space used by InputReader. */ class PointerControllerInterface { protected: diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index 15ba45945a..fcb56ef05c 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -188,8 +188,6 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { mOrientation = DISPLAY_ORIENTATION_0; - mDisplayWidth = 0; - mDisplayHeight = 0; const bool isOrientedDevice = (mParameters.orientationAware && mParameters.hasAssociatedDisplay); @@ -203,8 +201,6 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config->getDisplayViewportByType(ViewportType::INTERNAL); if (internalViewport) { mOrientation = getInverseRotation(internalViewport->orientation); - mDisplayWidth = internalViewport->deviceWidth; - mDisplayHeight = internalViewport->deviceHeight; } } @@ -335,14 +331,7 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER); if (moved) { - float dx = deltaX; - float dy = deltaY; - // Rotate the delta from InputReader's un-rotated coordinate space to - // PointerController's rotated coordinate space that is oriented with the - // viewport. - rotateDelta(getInverseRotation(mOrientation), &dx, &dy); - - mPointerController->move(dx, dy); + mPointerController->move(deltaX, deltaY); } if (buttonsChanged) { @@ -353,10 +342,6 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { } mPointerController->getPosition(&xCursorPosition, &yCursorPosition); - // Rotate the cursor position that is in PointerController's rotated coordinate space - // to InputReader's un-rotated coordinate space. - rotatePoint(mOrientation, xCursorPosition /*byRef*/, yCursorPosition /*byRef*/, - mDisplayWidth, mDisplayHeight); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h index 88e947f7d5..9a8ca01294 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.h +++ b/services/inputflinger/reader/mapper/CursorInputMapper.h @@ -105,8 +105,6 @@ private: VelocityControl mWheelYVelocityControl; int32_t mOrientation; - int32_t mDisplayWidth; - int32_t mDisplayHeight; std::shared_ptr mPointerController; diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h index 8c30e38908..31a3d2e172 100644 --- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h +++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h @@ -64,26 +64,6 @@ static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) { } } -// Rotates the given point (x, y) by the supplied orientation. The width and height are the -// dimensions of the surface prior to this rotation being applied. -static void rotatePoint(int32_t orientation, float& x, float& y, int32_t width, int32_t height) { - rotateDelta(orientation, &x, &y); - switch (orientation) { - case DISPLAY_ORIENTATION_90: - y += width; - break; - case DISPLAY_ORIENTATION_180: - x += width; - y += height; - break; - case DISPLAY_ORIENTATION_270: - x += height; - break; - default: - break; - } -} - // Returns true if the pointer should be reported as being down given the specified // button states. This determines whether the event is reported as a touch event. static bool isPointerDown(int32_t buttonState) { diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 3fe6fd130f..913c666a4a 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -1668,9 +1668,10 @@ void TouchInputMapper::updateTouchSpots() { mPointerController->fade(PointerControllerInterface::Transition::GRADUAL); mPointerController->setButtonState(mCurrentRawState.buttonState); - setTouchSpots(mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, - mCurrentCookedState.cookedPointerData.touchingIdBits, mViewport.displayId); + mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.touchingIdBits, + mViewport.displayId); } bool TouchInputMapper::isTouchScreen() { @@ -2410,9 +2411,10 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u } if (mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM) { - setTouchSpots(mPointerGesture.currentGestureCoords, - mPointerGesture.currentGestureIdToIndex, - mPointerGesture.currentGestureIdBits, mPointerController->getDisplayId()); + mPointerController->setSpots(mPointerGesture.currentGestureCoords, + mPointerGesture.currentGestureIdToIndex, + mPointerGesture.currentGestureIdBits, + mPointerController->getDisplayId()); } } else { mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER); @@ -2562,7 +2564,8 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u // the pointer is hovering again even if the user is not currently touching // the touch pad. This ensures that a view will receive a fresh hover enter // event after a tap. - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); PointerProperties pointerProperties; pointerProperties.clear(); @@ -2819,12 +2822,13 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi // Move the pointer using a relative motion. // When using spots, the click will occur at the position of the anchor // spot and all other spots will move there. - moveMouseCursor(deltaX, deltaY); + mPointerController->move(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); mPointerGesture.currentGestureMode = PointerGesture::Mode::BUTTON_CLICK_OR_DRAG; mPointerGesture.currentGestureIdBits.clear(); @@ -2850,7 +2854,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP_DRAG) && lastFingerCount == 1) { if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) { - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { #if DEBUG_GESTURES @@ -2918,7 +2923,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerGesture.currentGestureMode = PointerGesture::Mode::HOVER; if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP) { if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP_DRAG; @@ -2952,7 +2958,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi // Move the pointer using a relative motion. // When using spots, the hover or drag will occur at the position of the anchor spot. - moveMouseCursor(deltaX, deltaY); + mPointerController->move(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } @@ -2974,7 +2980,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi down = false; } - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); mPointerGesture.currentGestureIdBits.clear(); mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); @@ -3047,9 +3054,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mCurrentRawState.rawPointerData .getCentroidOfTouchingPointers(&mPointerGesture.referenceTouchX, &mPointerGesture.referenceTouchY); - auto [x, y] = getMouseCursorPosition(); - mPointerGesture.referenceGestureX = x; - mPointerGesture.referenceGestureY = y; + mPointerController->getPosition(&mPointerGesture.referenceGestureX, + &mPointerGesture.referenceGestureY); } // Clear the reference deltas for fingers not yet included in the reference calculation. @@ -3387,13 +3393,15 @@ void TouchInputMapper::dispatchPointerStylus(nsecs_t when, nsecs_t readTime, uin if (!mCurrentCookedState.stylusIdBits.isEmpty()) { uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit(); uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id]; - setMouseCursorPosition(mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(), - mCurrentCookedState.cookedPointerData.pointerCoords[index].getY()); + mPointerController + ->setPosition(mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(), + mCurrentCookedState.cookedPointerData.pointerCoords[index].getY()); hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id); down = !hovering; - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); mPointerSimple.currentCoords.copyFrom( mCurrentCookedState.cookedPointerData.pointerCoords[index]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); @@ -3434,7 +3442,7 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs_t readTime, uint rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY); mPointerVelocityControl.move(when, &deltaX, &deltaY); - moveMouseCursor(deltaX, deltaY); + mPointerController->move(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } @@ -3442,7 +3450,8 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs_t readTime, uint down = isPointerDown(mCurrentRawState.buttonState); hovering = !down; - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); mPointerSimple.currentCoords.copyFrom( mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); @@ -3482,7 +3491,8 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsecs_t readTime, uin } int32_t displayId = mPointerController->getDisplayId(); - auto [xCursorPosition, yCursorPosition] = getMouseCursorPosition(); + float xCursorPosition, yCursorPosition; + mPointerController->getPosition(&xCursorPosition, &yCursorPosition); if (mPointerSimple.down && !down) { mPointerSimple.down = false; @@ -3648,9 +3658,7 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, nsecs_t readTime, uint32_t p float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; if (mDeviceMode == DeviceMode::POINTER) { - auto [x, y] = getMouseCursorPosition(); - xCursorPosition = x; - yCursorPosition = y; + mPointerController->getPosition(&xCursorPosition, &yCursorPosition); } const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE); const int32_t deviceId = getDeviceId(); @@ -3999,56 +4007,4 @@ std::optional TouchInputMapper::getAssociatedDisplayId() { return std::nullopt; } -void TouchInputMapper::moveMouseCursor(float dx, float dy) const { - // Convert from InputReader's un-rotated coordinate space to PointerController's coordinate - // space that is oriented with the viewport. - rotateDelta(mViewport.orientation, &dx, &dy); - - mPointerController->move(dx, dy); -} - -std::pair TouchInputMapper::getMouseCursorPosition() const { - float x = 0; - float y = 0; - mPointerController->getPosition(&x, &y); - - if (!mViewport.isValid()) return {x, y}; - - // Convert from PointerController's rotated coordinate space that is oriented with the viewport - // to InputReader's un-rotated coordinate space. - const int32_t orientation = getInverseRotation(mViewport.orientation); - rotatePoint(orientation, x, y, mViewport.deviceWidth, mViewport.deviceHeight); - return {x, y}; -} - -void TouchInputMapper::setMouseCursorPosition(float x, float y) const { - // Convert from InputReader's un-rotated coordinate space to PointerController's rotated - // coordinate space that is oriented with the viewport. - rotatePoint(mViewport.orientation, x, y, mDisplayWidth, mDisplayHeight); - - mPointerController->setPosition(x, y); -} - -void TouchInputMapper::setTouchSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, - BitSet32 spotIdBits, int32_t displayId) { - std::array outSpotCoords{}; - - for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) { - const uint32_t index = spotIdToIndex[idBits.clearFirstMarkedBit()]; - float x = spotCoords[index].getX(); - float y = spotCoords[index].getY(); - float pressure = spotCoords[index].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); - - // Convert from InputReader's un-rotated coordinate space to PointerController's rotated - // coordinate space. - rotatePoint(mViewport.orientation, x, y, mDisplayWidth, mDisplayHeight); - - outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_X, x); - outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_Y, y); - outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); - } - - mPointerController->setSpots(outSpotCoords.data(), spotIdToIndex, spotIdBits, displayId); -} - } // namespace android diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index 496491b62d..9b020a609a 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -803,14 +803,6 @@ private: const char* modeToString(DeviceMode deviceMode); void rotateAndScale(float& x, float& y) const; - - // Wrapper methods for interfacing with PointerController. These are used to convert points - // between the coordinate spaces used by InputReader and PointerController, if they differ. - void moveMouseCursor(float dx, float dy) const; - std::pair getMouseCursorPosition() const; - void setMouseCursorPosition(float x, float y) const; - void setTouchSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, - BitSet32 spotIdBits, int32_t displayId); }; } // namespace android -- cgit v1.2.3-59-g8ed1b From 259a2122aeafea0f20bfcc7c9bcd089511a5aa56 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Wed, 17 Nov 2021 21:48:11 +0000 Subject: Revert "Change PointerController to display space" Revert submission 16194643-pointer-controller-in-display-space Reason for revert: b/206817973 Reverted Changes: I764c070ad:Change PointerController to display space I5e9e19c36:Change PointerController to display space Change-Id: If6e96f41873dd9601f49fc9f9f514a95394f3c58 --- include/input/Input.h | 5 - libs/input/Input.cpp | 12 +-- .../include/PointerControllerInterface.h | 3 +- .../reader/mapper/CursorInputMapper.cpp | 17 +++- .../inputflinger/reader/mapper/CursorInputMapper.h | 2 + .../reader/mapper/TouchCursorInputMapperCommon.h | 20 ++++ .../reader/mapper/TouchInputMapper.cpp | 110 ++++++++++++++------- .../inputflinger/reader/mapper/TouchInputMapper.h | 8 ++ 8 files changed, 130 insertions(+), 47 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index 5242dcb476..1e06257591 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -201,11 +201,6 @@ namespace android { class Parcel; #endif -/* - * Apply the given transform to the point without applying any translation/offset. - */ -vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy); - const char* inputEventTypeToString(int32_t type); std::string inputEventSourceToString(int32_t source); diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index cb93c92310..8974b22c86 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -60,6 +60,12 @@ float transformAngle(const ui::Transform& transform, float angleRadians) { return atan2f(transformedPoint.x, -transformedPoint.y); } +vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) { + const vec2 transformedXy = transform.transform(xy); + const vec2 transformedOrigin = transform.transform(0, 0); + return transformedXy - transformedOrigin; +} + bool shouldDisregardTransformation(uint32_t source) { // Do not apply any transformations to axes from joysticks or touchpads. return isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK) || @@ -114,12 +120,6 @@ int32_t IdGenerator::nextId() const { // --- InputEvent --- -vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) { - const vec2 transformedXy = transform.transform(xy); - const vec2 transformedOrigin = transform.transform(0, 0); - return transformedXy - transformedOrigin; -} - const char* inputEventTypeToString(int32_t type) { switch (type) { case AINPUT_EVENT_TYPE_KEY: { diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h index db4228d862..b1069497d3 100644 --- a/services/inputflinger/include/PointerControllerInterface.h +++ b/services/inputflinger/include/PointerControllerInterface.h @@ -30,8 +30,7 @@ namespace android { * fingers * * The pointer controller is responsible for providing synchronization and for tracking - * display orientation changes if needed. It works in the display panel's coordinate space, which - * is the same coordinate space used by InputReader. + * display orientation changes if needed. */ class PointerControllerInterface { protected: diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index fcb56ef05c..15ba45945a 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -188,6 +188,8 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { mOrientation = DISPLAY_ORIENTATION_0; + mDisplayWidth = 0; + mDisplayHeight = 0; const bool isOrientedDevice = (mParameters.orientationAware && mParameters.hasAssociatedDisplay); @@ -201,6 +203,8 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config->getDisplayViewportByType(ViewportType::INTERNAL); if (internalViewport) { mOrientation = getInverseRotation(internalViewport->orientation); + mDisplayWidth = internalViewport->deviceWidth; + mDisplayHeight = internalViewport->deviceHeight; } } @@ -331,7 +335,14 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER); if (moved) { - mPointerController->move(deltaX, deltaY); + float dx = deltaX; + float dy = deltaY; + // Rotate the delta from InputReader's un-rotated coordinate space to + // PointerController's rotated coordinate space that is oriented with the + // viewport. + rotateDelta(getInverseRotation(mOrientation), &dx, &dy); + + mPointerController->move(dx, dy); } if (buttonsChanged) { @@ -342,6 +353,10 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { } mPointerController->getPosition(&xCursorPosition, &yCursorPosition); + // Rotate the cursor position that is in PointerController's rotated coordinate space + // to InputReader's un-rotated coordinate space. + rotatePoint(mOrientation, xCursorPosition /*byRef*/, yCursorPosition /*byRef*/, + mDisplayWidth, mDisplayHeight); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h index 9a8ca01294..88e947f7d5 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.h +++ b/services/inputflinger/reader/mapper/CursorInputMapper.h @@ -105,6 +105,8 @@ private: VelocityControl mWheelYVelocityControl; int32_t mOrientation; + int32_t mDisplayWidth; + int32_t mDisplayHeight; std::shared_ptr mPointerController; diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h index 31a3d2e172..8c30e38908 100644 --- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h +++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h @@ -64,6 +64,26 @@ static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) { } } +// Rotates the given point (x, y) by the supplied orientation. The width and height are the +// dimensions of the surface prior to this rotation being applied. +static void rotatePoint(int32_t orientation, float& x, float& y, int32_t width, int32_t height) { + rotateDelta(orientation, &x, &y); + switch (orientation) { + case DISPLAY_ORIENTATION_90: + y += width; + break; + case DISPLAY_ORIENTATION_180: + x += width; + y += height; + break; + case DISPLAY_ORIENTATION_270: + x += height; + break; + default: + break; + } +} + // Returns true if the pointer should be reported as being down given the specified // button states. This determines whether the event is reported as a touch event. static bool isPointerDown(int32_t buttonState) { diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 913c666a4a..3fe6fd130f 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -1668,10 +1668,9 @@ void TouchInputMapper::updateTouchSpots() { mPointerController->fade(PointerControllerInterface::Transition::GRADUAL); mPointerController->setButtonState(mCurrentRawState.buttonState); - mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, - mCurrentCookedState.cookedPointerData.touchingIdBits, - mViewport.displayId); + setTouchSpots(mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.touchingIdBits, mViewport.displayId); } bool TouchInputMapper::isTouchScreen() { @@ -2411,10 +2410,9 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u } if (mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM) { - mPointerController->setSpots(mPointerGesture.currentGestureCoords, - mPointerGesture.currentGestureIdToIndex, - mPointerGesture.currentGestureIdBits, - mPointerController->getDisplayId()); + setTouchSpots(mPointerGesture.currentGestureCoords, + mPointerGesture.currentGestureIdToIndex, + mPointerGesture.currentGestureIdBits, mPointerController->getDisplayId()); } } else { mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER); @@ -2564,8 +2562,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u // the pointer is hovering again even if the user is not currently touching // the touch pad. This ensures that a view will receive a fresh hover enter // event after a tap. - float x, y; - mPointerController->getPosition(&x, &y); + auto [x, y] = getMouseCursorPosition(); PointerProperties pointerProperties; pointerProperties.clear(); @@ -2822,13 +2819,12 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi // Move the pointer using a relative motion. // When using spots, the click will occur at the position of the anchor // spot and all other spots will move there. - mPointerController->move(deltaX, deltaY); + moveMouseCursor(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } - float x, y; - mPointerController->getPosition(&x, &y); + auto [x, y] = getMouseCursorPosition(); mPointerGesture.currentGestureMode = PointerGesture::Mode::BUTTON_CLICK_OR_DRAG; mPointerGesture.currentGestureIdBits.clear(); @@ -2854,8 +2850,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP_DRAG) && lastFingerCount == 1) { if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) { - float x, y; - mPointerController->getPosition(&x, &y); + auto [x, y] = getMouseCursorPosition(); if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { #if DEBUG_GESTURES @@ -2923,8 +2918,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerGesture.currentGestureMode = PointerGesture::Mode::HOVER; if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP) { if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { - float x, y; - mPointerController->getPosition(&x, &y); + auto [x, y] = getMouseCursorPosition(); if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP_DRAG; @@ -2958,7 +2952,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi // Move the pointer using a relative motion. // When using spots, the hover or drag will occur at the position of the anchor spot. - mPointerController->move(deltaX, deltaY); + moveMouseCursor(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } @@ -2980,8 +2974,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi down = false; } - float x, y; - mPointerController->getPosition(&x, &y); + auto [x, y] = getMouseCursorPosition(); mPointerGesture.currentGestureIdBits.clear(); mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); @@ -3054,8 +3047,9 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mCurrentRawState.rawPointerData .getCentroidOfTouchingPointers(&mPointerGesture.referenceTouchX, &mPointerGesture.referenceTouchY); - mPointerController->getPosition(&mPointerGesture.referenceGestureX, - &mPointerGesture.referenceGestureY); + auto [x, y] = getMouseCursorPosition(); + mPointerGesture.referenceGestureX = x; + mPointerGesture.referenceGestureY = y; } // Clear the reference deltas for fingers not yet included in the reference calculation. @@ -3393,15 +3387,13 @@ void TouchInputMapper::dispatchPointerStylus(nsecs_t when, nsecs_t readTime, uin if (!mCurrentCookedState.stylusIdBits.isEmpty()) { uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit(); uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id]; - mPointerController - ->setPosition(mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(), - mCurrentCookedState.cookedPointerData.pointerCoords[index].getY()); + setMouseCursorPosition(mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(), + mCurrentCookedState.cookedPointerData.pointerCoords[index].getY()); hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id); down = !hovering; - float x, y; - mPointerController->getPosition(&x, &y); + auto [x, y] = getMouseCursorPosition(); mPointerSimple.currentCoords.copyFrom( mCurrentCookedState.cookedPointerData.pointerCoords[index]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); @@ -3442,7 +3434,7 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs_t readTime, uint rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY); mPointerVelocityControl.move(when, &deltaX, &deltaY); - mPointerController->move(deltaX, deltaY); + moveMouseCursor(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } @@ -3450,8 +3442,7 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs_t readTime, uint down = isPointerDown(mCurrentRawState.buttonState); hovering = !down; - float x, y; - mPointerController->getPosition(&x, &y); + auto [x, y] = getMouseCursorPosition(); mPointerSimple.currentCoords.copyFrom( mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); @@ -3491,8 +3482,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsecs_t readTime, uin } int32_t displayId = mPointerController->getDisplayId(); - float xCursorPosition, yCursorPosition; - mPointerController->getPosition(&xCursorPosition, &yCursorPosition); + auto [xCursorPosition, yCursorPosition] = getMouseCursorPosition(); if (mPointerSimple.down && !down) { mPointerSimple.down = false; @@ -3658,7 +3648,9 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, nsecs_t readTime, uint32_t p float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; if (mDeviceMode == DeviceMode::POINTER) { - mPointerController->getPosition(&xCursorPosition, &yCursorPosition); + auto [x, y] = getMouseCursorPosition(); + xCursorPosition = x; + yCursorPosition = y; } const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE); const int32_t deviceId = getDeviceId(); @@ -4007,4 +3999,56 @@ std::optional TouchInputMapper::getAssociatedDisplayId() { return std::nullopt; } +void TouchInputMapper::moveMouseCursor(float dx, float dy) const { + // Convert from InputReader's un-rotated coordinate space to PointerController's coordinate + // space that is oriented with the viewport. + rotateDelta(mViewport.orientation, &dx, &dy); + + mPointerController->move(dx, dy); +} + +std::pair TouchInputMapper::getMouseCursorPosition() const { + float x = 0; + float y = 0; + mPointerController->getPosition(&x, &y); + + if (!mViewport.isValid()) return {x, y}; + + // Convert from PointerController's rotated coordinate space that is oriented with the viewport + // to InputReader's un-rotated coordinate space. + const int32_t orientation = getInverseRotation(mViewport.orientation); + rotatePoint(orientation, x, y, mViewport.deviceWidth, mViewport.deviceHeight); + return {x, y}; +} + +void TouchInputMapper::setMouseCursorPosition(float x, float y) const { + // Convert from InputReader's un-rotated coordinate space to PointerController's rotated + // coordinate space that is oriented with the viewport. + rotatePoint(mViewport.orientation, x, y, mDisplayWidth, mDisplayHeight); + + mPointerController->setPosition(x, y); +} + +void TouchInputMapper::setTouchSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, + BitSet32 spotIdBits, int32_t displayId) { + std::array outSpotCoords{}; + + for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) { + const uint32_t index = spotIdToIndex[idBits.clearFirstMarkedBit()]; + float x = spotCoords[index].getX(); + float y = spotCoords[index].getY(); + float pressure = spotCoords[index].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); + + // Convert from InputReader's un-rotated coordinate space to PointerController's rotated + // coordinate space. + rotatePoint(mViewport.orientation, x, y, mDisplayWidth, mDisplayHeight); + + outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_X, x); + outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_Y, y); + outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); + } + + mPointerController->setSpots(outSpotCoords.data(), spotIdToIndex, spotIdBits, displayId); +} + } // namespace android diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index 9b020a609a..496491b62d 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -803,6 +803,14 @@ private: const char* modeToString(DeviceMode deviceMode); void rotateAndScale(float& x, float& y) const; + + // Wrapper methods for interfacing with PointerController. These are used to convert points + // between the coordinate spaces used by InputReader and PointerController, if they differ. + void moveMouseCursor(float dx, float dy) const; + std::pair getMouseCursorPosition() const; + void setMouseCursorPosition(float x, float y) const; + void setTouchSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, + BitSet32 spotIdBits, int32_t displayId); }; } // namespace android -- cgit v1.2.3-59-g8ed1b From f6b4ba6692807b35e909efaca1d8201bcdd5c397 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Tue, 9 Nov 2021 12:46:10 -0800 Subject: SF: Set up libscheduler headers Start pulling Scheduler sources into a libscheduler target akin to librenderengine and libcompositionengine. Bug: 185535769 Test: Build Change-Id: I8ee871cce96209c8c53601152501129b09c5e46f --- services/surfaceflinger/Android.bp | 2 +- .../surfaceflinger/DisplayHardware/DisplayMode.h | 15 +-- services/surfaceflinger/Fps.h | 128 --------------------- services/surfaceflinger/FrameTimeline/Android.bp | 3 + .../surfaceflinger/FrameTimeline/FrameTimeline.h | 15 ++- services/surfaceflinger/Layer.h | 7 +- services/surfaceflinger/RefreshRateOverlay.cpp | 2 +- services/surfaceflinger/RefreshRateOverlay.h | 12 +- services/surfaceflinger/Scheduler/Android.bp | 26 +++++ services/surfaceflinger/Scheduler/LayerInfo.h | 10 +- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 11 +- .../surfaceflinger/Scheduler/RefreshRateStats.h | 3 +- services/surfaceflinger/Scheduler/Seamlessness.h | 54 --------- services/surfaceflinger/Scheduler/VSyncTracker.h | 4 +- .../surfaceflinger/Scheduler/VsyncConfiguration.h | 3 +- .../Scheduler/include/scheduler/Fps.h | 128 +++++++++++++++++++++ .../Scheduler/include/scheduler/Seamlessness.h | 52 +++++++++ services/surfaceflinger/SurfaceFlinger.h | 5 +- services/surfaceflinger/SurfaceFlingerFactory.h | 10 +- services/surfaceflinger/TimeStats/Android.bp | 6 + services/surfaceflinger/TimeStats/TimeStats.h | 12 +- services/surfaceflinger/tests/unittests/Android.bp | 3 +- services/surfaceflinger/tests/unittests/FpsOps.h | 2 +- .../surfaceflinger/tests/unittests/FpsTest.cpp | 7 +- .../tests/unittests/LayerInfoTest.cpp | 3 +- 25 files changed, 289 insertions(+), 234 deletions(-) delete mode 100644 services/surfaceflinger/Fps.h create mode 100644 services/surfaceflinger/Scheduler/Android.bp delete mode 100644 services/surfaceflinger/Scheduler/Seamlessness.h create mode 100644 services/surfaceflinger/Scheduler/include/scheduler/Fps.h create mode 100644 services/surfaceflinger/Scheduler/include/scheduler/Seamlessness.h diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index fb42cc02eb..29636f84f5 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -78,10 +78,10 @@ cc_defaults { "libframetimeline", "libperfetto_client_experimental", "librenderengine", + "libscheduler", "libserviceutils", "libtonemap", "libtrace_proto", - "libaidlcommonsupport", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h index 5de622b318..0ab9605fca 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayMode.h +++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h @@ -16,9 +16,9 @@ #pragma once -#include "DisplayHardware/Hal.h" -#include "Fps.h" -#include "Scheduler/StrongTyping.h" +#include +#include +#include #include #include @@ -27,9 +27,10 @@ #include #include -#include -#include -#include +#include + +#include "DisplayHardware/Hal.h" +#include "Scheduler/StrongTyping.h" namespace android { @@ -161,4 +162,4 @@ inline std::string to_string(const DisplayMode& mode) { mode.getDpiY(), mode.getGroup()); } -} // namespace android \ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/Fps.h b/services/surfaceflinger/Fps.h deleted file mode 100644 index 639b3e5ed8..0000000000 --- a/services/surfaceflinger/Fps.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include - -#include -#include - -namespace android { - -// Frames per second, stored as floating-point frequency. Provides conversion from/to period in -// nanoseconds, and relational operators with precision threshold. -// -// const Fps fps = 60_Hz; -// -// using namespace fps_approx_ops; -// assert(fps == Fps::fromPeriodNsecs(16'666'667)); -// -class Fps { -public: - constexpr Fps() = default; - - static constexpr Fps fromValue(float frequency) { - return frequency > 0.f ? Fps(frequency, static_cast(1e9f / frequency)) : Fps(); - } - - static constexpr Fps fromPeriodNsecs(nsecs_t period) { - return period > 0 ? Fps(1e9f / period, period) : Fps(); - } - - constexpr bool isValid() const { return mFrequency > 0.f; } - - constexpr float getValue() const { return mFrequency; } - int getIntValue() const { return static_cast(std::round(mFrequency)); } - - constexpr nsecs_t getPeriodNsecs() const { return mPeriod; } - -private: - constexpr Fps(float frequency, nsecs_t period) : mFrequency(frequency), mPeriod(period) {} - - float mFrequency = 0.f; - nsecs_t mPeriod = 0; -}; - -static_assert(std::is_trivially_copyable_v); - -constexpr Fps operator""_Hz(unsigned long long frequency) { - return Fps::fromValue(static_cast(frequency)); -} - -constexpr Fps operator""_Hz(long double frequency) { - return Fps::fromValue(static_cast(frequency)); -} - -inline bool isStrictlyLess(Fps lhs, Fps rhs) { - return lhs.getValue() < rhs.getValue(); -} - -// Does not satisfy equivalence relation. -inline bool isApproxEqual(Fps lhs, Fps rhs) { - // TODO(b/185536303): Replace with ULP distance. - return std::abs(lhs.getValue() - rhs.getValue()) < 0.001f; -} - -// Does not satisfy strict weak order. -inline bool isApproxLess(Fps lhs, Fps rhs) { - return isStrictlyLess(lhs, rhs) && !isApproxEqual(lhs, rhs); -} - -namespace fps_approx_ops { - -inline bool operator==(Fps lhs, Fps rhs) { - return isApproxEqual(lhs, rhs); -} - -inline bool operator<(Fps lhs, Fps rhs) { - return isApproxLess(lhs, rhs); -} - -inline bool operator!=(Fps lhs, Fps rhs) { - return !isApproxEqual(lhs, rhs); -} - -inline bool operator>(Fps lhs, Fps rhs) { - return isApproxLess(rhs, lhs); -} - -inline bool operator<=(Fps lhs, Fps rhs) { - return !isApproxLess(rhs, lhs); -} - -inline bool operator>=(Fps lhs, Fps rhs) { - return !isApproxLess(lhs, rhs); -} - -} // namespace fps_approx_ops - -struct FpsApproxEqual { - bool operator()(Fps lhs, Fps rhs) const { return isApproxEqual(lhs, rhs); } -}; - -inline std::string to_string(Fps fps) { - return base::StringPrintf("%.2f Hz", fps.getValue()); -} - -inline std::ostream& operator<<(std::ostream& stream, Fps fps) { - return stream << to_string(fps); -} - -} // namespace android diff --git a/services/surfaceflinger/FrameTimeline/Android.bp b/services/surfaceflinger/FrameTimeline/Android.bp index 10a58333f9..2d4ec04cfc 100644 --- a/services/surfaceflinger/FrameTimeline/Android.bp +++ b/services/surfaceflinger/FrameTimeline/Android.bp @@ -13,6 +13,9 @@ cc_library_static { srcs: [ "FrameTimeline.cpp", ], + header_libs: [ + "libscheduler_headers", + ], shared_libs: [ "android.hardware.graphics.composer@2.4", "libbase", diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h index 139f91f3bc..d08344ef6e 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h @@ -16,8 +16,14 @@ #pragma once -#include <../Fps.h> -#include <../TimeStats/TimeStats.h> +#include +#include +#include +#include +#include +#include +#include + #include #include #include @@ -28,8 +34,9 @@ #include #include -#include -#include +#include + +#include "../TimeStats/TimeStats.h" namespace android::frametimeline { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index bda1c28d27..041b439ac7 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -18,7 +18,6 @@ #pragma once #include -#include #include #include #include @@ -39,6 +38,10 @@ #include #include +#include +#include +#include + #include #include #include @@ -49,13 +52,11 @@ #include "ClientCache.h" #include "DisplayHardware/ComposerHal.h" #include "DisplayHardware/HWComposer.h" -#include "Fps.h" #include "FrameTracker.h" #include "LayerVector.h" #include "MonitoredProducer.h" #include "RenderArea.h" #include "Scheduler/LayerInfo.h" -#include "Scheduler/Seamlessness.h" #include "SurfaceFlinger.h" #include "Tracing/LayerTracing.h" #include "TransactionCallbackInvoker.h" diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 2502d66a67..712ab168a2 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -276,7 +276,7 @@ void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) { t.apply(); } -void RefreshRateOverlay::changeRefreshRate(const Fps& fps) { +void RefreshRateOverlay::changeRefreshRate(Fps fps) { mCurrentFps = fps.getIntValue(); auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame]; SurfaceComposerClient::Transaction t; diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h index 65d446c751..381df37903 100644 --- a/services/surfaceflinger/RefreshRateOverlay.h +++ b/services/surfaceflinger/RefreshRateOverlay.h @@ -16,6 +16,10 @@ #pragma once +#include +#include +#include + #include #include #include @@ -23,11 +27,7 @@ #include #include -#include -#include -#include - -#include "Fps.h" +#include namespace android { @@ -45,7 +45,7 @@ public: void setLayerStack(ui::LayerStack); void setViewport(ui::Size); - void changeRefreshRate(const Fps&); + void changeRefreshRate(Fps); void animate(); private: diff --git a/services/surfaceflinger/Scheduler/Android.bp b/services/surfaceflinger/Scheduler/Android.bp new file mode 100644 index 0000000000..2318a575eb --- /dev/null +++ b/services/surfaceflinger/Scheduler/Android.bp @@ -0,0 +1,26 @@ +cc_defaults { + name: "libscheduler_defaults", + defaults: ["surfaceflinger_defaults"], + cflags: [ + "-DLOG_TAG=\"Scheduler\"", + "-DATRACE_TAG=ATRACE_TAG_GRAPHICS", + ], + shared_libs: [ + "libbase", + "libutils", + ], +} + +cc_library_headers { + name: "libscheduler_headers", + defaults: ["libscheduler_defaults"], + export_include_dirs: ["include"], +} + +cc_library_static { + name: "libscheduler", + defaults: ["libscheduler_defaults"], + srcs: [], + local_include_dirs: ["include"], + export_include_dirs: ["include"], +} diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index 92abbae532..18ed95ec0f 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -16,15 +16,19 @@ #pragma once +#include +#include +#include +#include +#include + #include #include -#include -#include +#include #include "LayerHistory.h" #include "RefreshRateConfigs.h" -#include "Scheduler/Seamlessness.h" #include "SchedulerUtils.h" namespace android { diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 53472efae9..85c31e8d5b 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -16,20 +16,21 @@ #pragma once -#include -#include - #include #include #include #include +#include +#include + +#include +#include + #include "DisplayHardware/DisplayMode.h" #include "DisplayHardware/HWComposer.h" -#include "Fps.h" #include "Scheduler/OneShotTimer.h" #include "Scheduler/SchedulerUtils.h" -#include "Scheduler/Seamlessness.h" #include "Scheduler/StrongTyping.h" namespace android::scheduler { diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h index 80aa96fd63..23ebb061e4 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateStats.h +++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h @@ -23,7 +23,8 @@ #include #include -#include "Fps.h" +#include + #include "Scheduler/SchedulerUtils.h" #include "TimeStats/TimeStats.h" diff --git a/services/surfaceflinger/Scheduler/Seamlessness.h b/services/surfaceflinger/Scheduler/Seamlessness.h deleted file mode 100644 index 3e42a4db37..0000000000 --- a/services/surfaceflinger/Scheduler/Seamlessness.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -namespace android { -namespace scheduler { - -// The seamlessness requirement of a Layer. -enum class Seamlessness { - // Indicates a requirement for a seamless mode switch. - OnlySeamless, - // Indicates that both seamless and seamed mode switches are allowed. - SeamedAndSeamless, - // Indicates no preference for seamlessness. For such layers the system will - // prefer seamless switches, but also non-seamless switches to the group of the - // default config are allowed. - Default -}; - -inline std::string toString(Seamlessness seamlessness) { - switch (seamlessness) { - case Seamlessness::OnlySeamless: - return "OnlySeamless"; - case Seamlessness::SeamedAndSeamless: - return "SeamedAndSeamless"; - case Seamlessness::Default: - return "Default"; - } -} - -// Used by gtest -inline std::ostream& operator<<(std::ostream& os, Seamlessness val) { - return os << toString(val); -} - -} // namespace scheduler -} // namespace android diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h index 95750ad5cc..76315d2b5b 100644 --- a/services/surfaceflinger/Scheduler/VSyncTracker.h +++ b/services/surfaceflinger/Scheduler/VSyncTracker.h @@ -17,7 +17,9 @@ #pragma once #include -#include "Fps.h" + +#include + #include "VSyncDispatch.h" namespace android::scheduler { diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.h b/services/surfaceflinger/Scheduler/VsyncConfiguration.h index 844751270e..02ebd70272 100644 --- a/services/surfaceflinger/Scheduler/VsyncConfiguration.h +++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.h @@ -23,7 +23,8 @@ #include #include -#include "Fps.h" +#include + #include "VsyncModulator.h" namespace android::scheduler { diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Fps.h b/services/surfaceflinger/Scheduler/include/scheduler/Fps.h new file mode 100644 index 0000000000..639b3e5ed8 --- /dev/null +++ b/services/surfaceflinger/Scheduler/include/scheduler/Fps.h @@ -0,0 +1,128 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace android { + +// Frames per second, stored as floating-point frequency. Provides conversion from/to period in +// nanoseconds, and relational operators with precision threshold. +// +// const Fps fps = 60_Hz; +// +// using namespace fps_approx_ops; +// assert(fps == Fps::fromPeriodNsecs(16'666'667)); +// +class Fps { +public: + constexpr Fps() = default; + + static constexpr Fps fromValue(float frequency) { + return frequency > 0.f ? Fps(frequency, static_cast(1e9f / frequency)) : Fps(); + } + + static constexpr Fps fromPeriodNsecs(nsecs_t period) { + return period > 0 ? Fps(1e9f / period, period) : Fps(); + } + + constexpr bool isValid() const { return mFrequency > 0.f; } + + constexpr float getValue() const { return mFrequency; } + int getIntValue() const { return static_cast(std::round(mFrequency)); } + + constexpr nsecs_t getPeriodNsecs() const { return mPeriod; } + +private: + constexpr Fps(float frequency, nsecs_t period) : mFrequency(frequency), mPeriod(period) {} + + float mFrequency = 0.f; + nsecs_t mPeriod = 0; +}; + +static_assert(std::is_trivially_copyable_v); + +constexpr Fps operator""_Hz(unsigned long long frequency) { + return Fps::fromValue(static_cast(frequency)); +} + +constexpr Fps operator""_Hz(long double frequency) { + return Fps::fromValue(static_cast(frequency)); +} + +inline bool isStrictlyLess(Fps lhs, Fps rhs) { + return lhs.getValue() < rhs.getValue(); +} + +// Does not satisfy equivalence relation. +inline bool isApproxEqual(Fps lhs, Fps rhs) { + // TODO(b/185536303): Replace with ULP distance. + return std::abs(lhs.getValue() - rhs.getValue()) < 0.001f; +} + +// Does not satisfy strict weak order. +inline bool isApproxLess(Fps lhs, Fps rhs) { + return isStrictlyLess(lhs, rhs) && !isApproxEqual(lhs, rhs); +} + +namespace fps_approx_ops { + +inline bool operator==(Fps lhs, Fps rhs) { + return isApproxEqual(lhs, rhs); +} + +inline bool operator<(Fps lhs, Fps rhs) { + return isApproxLess(lhs, rhs); +} + +inline bool operator!=(Fps lhs, Fps rhs) { + return !isApproxEqual(lhs, rhs); +} + +inline bool operator>(Fps lhs, Fps rhs) { + return isApproxLess(rhs, lhs); +} + +inline bool operator<=(Fps lhs, Fps rhs) { + return !isApproxLess(rhs, lhs); +} + +inline bool operator>=(Fps lhs, Fps rhs) { + return !isApproxLess(lhs, rhs); +} + +} // namespace fps_approx_ops + +struct FpsApproxEqual { + bool operator()(Fps lhs, Fps rhs) const { return isApproxEqual(lhs, rhs); } +}; + +inline std::string to_string(Fps fps) { + return base::StringPrintf("%.2f Hz", fps.getValue()); +} + +inline std::ostream& operator<<(std::ostream& stream, Fps fps) { + return stream << to_string(fps); +} + +} // namespace android diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Seamlessness.h b/services/surfaceflinger/Scheduler/include/scheduler/Seamlessness.h new file mode 100644 index 0000000000..d7667ec9c6 --- /dev/null +++ b/services/surfaceflinger/Scheduler/include/scheduler/Seamlessness.h @@ -0,0 +1,52 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace android::scheduler { + +// The seamlessness requirement of a Layer. +enum class Seamlessness { + // Indicates a requirement for a seamless mode switch. + OnlySeamless, + // Indicates that both seamless and seamed mode switches are allowed. + SeamedAndSeamless, + // Indicates no preference for seamlessness. For such layers the system will + // prefer seamless switches, but also non-seamless switches to the group of the + // default config are allowed. + Default +}; + +inline std::string toString(Seamlessness seamlessness) { + switch (seamlessness) { + case Seamlessness::OnlySeamless: + return "OnlySeamless"; + case Seamlessness::SeamedAndSeamless: + return "SeamedAndSeamless"; + case Seamlessness::Default: + return "Default"; + } +} + +// Used by gtest +inline std::ostream& operator<<(std::ostream& os, Seamlessness val) { + return os << toString(val); +} + +} // namespace android::scheduler diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6093be91f9..3037593d6c 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -23,7 +23,6 @@ */ #include -#include #include #include #include @@ -47,13 +46,15 @@ #include #include +#include +#include + #include "ClientCache.h" #include "DisplayDevice.h" #include "DisplayHardware/HWC2.h" #include "DisplayHardware/PowerAdvisor.h" #include "DisplayIdGenerator.h" #include "Effects/Daltonizer.h" -#include "Fps.h" #include "FrameTracker.h" #include "LayerVector.h" #include "Scheduler/RefreshRateConfigs.h" diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index e670f37189..e509cc9385 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -16,16 +16,16 @@ #pragma once -#include "Fps.h" - -#include -#include - #include #include #include #include +#include +#include + +#include + namespace android { typedef int32_t PixelFormat; diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp index bcc3e4e52a..4686eed54c 100644 --- a/services/surfaceflinger/TimeStats/Android.bp +++ b/services/surfaceflinger/TimeStats/Android.bp @@ -12,6 +12,9 @@ cc_library { srcs: [ "TimeStats.cpp", ], + header_libs: [ + "libscheduler_headers", + ], shared_libs: [ "android.hardware.graphics.composer@2.4", "libbase", @@ -24,6 +27,9 @@ cc_library { "libutils", ], export_include_dirs: ["."], + export_header_lib_headers: [ + "libscheduler_headers", + ], export_shared_lib_headers: [ "libtimestats_proto", ], diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index bdeaeb8468..23f19b5cfd 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -17,8 +17,12 @@ #pragma once #include +#include +#include +#include +#include +#include -#include <../Fps.h> #include #include #include @@ -27,11 +31,7 @@ #include #include -#include -#include -#include -#include -#include +#include using namespace android::surfaceflinger; diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 3dc6d8b5c1..5c9e1c5ad9 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -135,8 +135,9 @@ cc_test { "libgui_mocks", "liblayers_proto", "libperfetto_client_experimental", - "librenderengine_mocks", "librenderengine", + "librenderengine_mocks", + "libscheduler", "libserviceutils", "libtimestats", "libtimestats_atoms_proto", diff --git a/services/surfaceflinger/tests/unittests/FpsOps.h b/services/surfaceflinger/tests/unittests/FpsOps.h index 23c2841efc..7c737dce28 100644 --- a/services/surfaceflinger/tests/unittests/FpsOps.h +++ b/services/surfaceflinger/tests/unittests/FpsOps.h @@ -16,7 +16,7 @@ #pragma once -#include "Fps.h" +#include namespace android { diff --git a/services/surfaceflinger/tests/unittests/FpsTest.cpp b/services/surfaceflinger/tests/unittests/FpsTest.cpp index b44dd89229..88b74d2a22 100644 --- a/services/surfaceflinger/tests/unittests/FpsTest.cpp +++ b/services/surfaceflinger/tests/unittests/FpsTest.cpp @@ -14,12 +14,13 @@ * limitations under the License. */ -#include "Fps.h" -#include "FpsOps.h" - #include #include +#include + +#include "FpsOps.h" + namespace android { TEST(FpsTest, construct) { diff --git a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp index f25994e399..5c2d2e1f43 100644 --- a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp @@ -19,7 +19,8 @@ #include -#include "Fps.h" +#include + #include "FpsOps.h" #include "Scheduler/LayerHistory.h" #include "Scheduler/LayerInfo.h" -- cgit v1.2.3-59-g8ed1b From c77162c2df4ea1d1fb3310e5f16cbcffe73f088d Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Tue, 16 Nov 2021 17:13:08 -0500 Subject: Move sysprop check for RenderEngineType into SF As brought up in I455d5d613ccaa210dc748969e025dc86c78080b8, we should read the sysprop in SF, so that clients (e.g. tests or benchmarks) that specify using a particular Type actually use that type, regardless of any sysprop set. If the sysprop is not set, or is set to an invalid value, just respect the default that is already set by RenderEngineCreationArgs::Builder. Bug: 193240340 Test: adb shell setprop debug.renderengine.backend verify via logcat that the proper type is used Change-Id: Iaf425fde6333f54d5b190df66cb7a79e1d491e63 --- libs/renderengine/RenderEngine.cpp | 18 +-------- .../include/renderengine/RenderEngine.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 47 ++++++++++++++++------ 3 files changed, 36 insertions(+), 31 deletions(-) diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp index 65d48951c6..c7ad058ab9 100644 --- a/libs/renderengine/RenderEngine.cpp +++ b/libs/renderengine/RenderEngine.cpp @@ -26,23 +26,7 @@ namespace android { namespace renderengine { -std::unique_ptr RenderEngine::create(RenderEngineCreationArgs args) { - // Keep the ability to override by PROPERTIES: - char prop[PROPERTY_VALUE_MAX]; - property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, ""); - if (strcmp(prop, "gles") == 0) { - args.renderEngineType = RenderEngineType::GLES; - } - if (strcmp(prop, "threaded") == 0) { - args.renderEngineType = RenderEngineType::THREADED; - } - if (strcmp(prop, "skiagl") == 0) { - args.renderEngineType = RenderEngineType::SKIA_GL; - } - if (strcmp(prop, "skiaglthreaded") == 0) { - args.renderEngineType = RenderEngineType::SKIA_GL_THREADED; - } - +std::unique_ptr RenderEngine::create(const RenderEngineCreationArgs& args) { switch (args.renderEngineType) { case RenderEngineType::THREADED: ALOGD("Threaded RenderEngine with GLES Backend"); diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 6b85c57069..b9cc6485e5 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -99,7 +99,7 @@ public: SKIA_GL_THREADED = 4, }; - static std::unique_ptr create(RenderEngineCreationArgs args); + static std::unique_ptr create(const RenderEngineCreationArgs& args); virtual ~RenderEngine() = 0; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 45e0a3f616..4752caf138 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -772,6 +772,25 @@ void SurfaceFlinger::deleteTextureAsync(uint32_t texture) { ATRACE_INT("TexturePoolSize", mTexturePool.size()); } +static std::optional +chooseRenderEngineTypeViaSysProp() { + char prop[PROPERTY_VALUE_MAX]; + property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, ""); + + if (strcmp(prop, "gles") == 0) { + return renderengine::RenderEngine::RenderEngineType::GLES; + } else if (strcmp(prop, "threaded") == 0) { + return renderengine::RenderEngine::RenderEngineType::THREADED; + } else if (strcmp(prop, "skiagl") == 0) { + return renderengine::RenderEngine::RenderEngineType::SKIA_GL; + } else if (strcmp(prop, "skiaglthreaded") == 0) { + return renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED; + } else { + ALOGE("Unrecognized RenderEngineType %s; ignoring!", prop); + return {}; + } +} + // Do not call property_set on main thread which will be blocked by init // Use StartPropertySetThread instead. void SurfaceFlinger::init() { @@ -782,19 +801,21 @@ void SurfaceFlinger::init() { // Get a RenderEngine for the given display / config (can't fail) // TODO(b/77156734): We need to stop casting and use HAL types when possible. // Sending maxFrameBufferAcquiredBuffers as the cache size is tightly tuned to single-display. - mCompositionEngine->setRenderEngine(renderengine::RenderEngine::create( - renderengine::RenderEngineCreationArgs::Builder() - .setPixelFormat(static_cast(defaultCompositionPixelFormat)) - .setImageCacheSize(maxFrameBufferAcquiredBuffers) - .setUseColorManagerment(useColorManagement) - .setEnableProtectedContext(enable_protected_contents(false)) - .setPrecacheToneMapperShaderOnly(false) - .setSupportsBackgroundBlur(mSupportsBlur) - .setContextPriority( - useContextPriority - ? renderengine::RenderEngine::ContextPriority::REALTIME - : renderengine::RenderEngine::ContextPriority::MEDIUM) - .build())); + auto builder = renderengine::RenderEngineCreationArgs::Builder() + .setPixelFormat(static_cast(defaultCompositionPixelFormat)) + .setImageCacheSize(maxFrameBufferAcquiredBuffers) + .setUseColorManagerment(useColorManagement) + .setEnableProtectedContext(enable_protected_contents(false)) + .setPrecacheToneMapperShaderOnly(false) + .setSupportsBackgroundBlur(mSupportsBlur) + .setContextPriority( + useContextPriority + ? renderengine::RenderEngine::ContextPriority::REALTIME + : renderengine::RenderEngine::ContextPriority::MEDIUM); + if (auto type = chooseRenderEngineTypeViaSysProp()) { + builder.setRenderEngineType(type.value()); + } + mCompositionEngine->setRenderEngine(renderengine::RenderEngine::create(builder.build())); mMaxRenderTargetSize = std::min(getRenderEngine().getMaxTextureSize(), getRenderEngine().getMaxViewportDims()); -- cgit v1.2.3-59-g8ed1b From f2dace7ba5f849f14fd63b5bfe873056d3e44721 Mon Sep 17 00:00:00 2001 From: chaviw Date: Wed, 17 Nov 2021 17:36:50 -0600 Subject: Only add commit callback when using sync transaction There's no need to add a commit callback when we're not syncing since the callback won't actually do anything. Instead only add a commit callback when a sync transaction has been requested. Test: BLASTBufferQueueTest Bug: 205278630 Change-Id: Ib7345f2581b6e4ce8923531aebcd457c14d86027 --- libs/gui/BLASTBufferQueue.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 55703214a5..f05426f7cf 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -507,7 +507,6 @@ void BLASTBufferQueue::acquireNextBufferLocked( // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback. incStrong((void*)transactionCallbackThunk); - incStrong((void*)transactionCommittedCallbackThunk); const bool sizeHasChanged = mRequestedSize != mSize; mSize = mRequestedSize; @@ -527,7 +526,7 @@ void BLASTBufferQueue::acquireNextBufferLocked( t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata); t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage); t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast(this)); - t->addTransactionCommittedCallback(transactionCommittedCallbackThunk, static_cast(this)); + mSurfaceControlsWithPendingCallback.push(mSurfaceControl); if (updateDestinationFrame) { @@ -658,6 +657,13 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { if (syncTransactionSet) { acquireNextBufferLocked(mSyncTransaction); + + // Only need a commit callback when syncing to ensure the buffer that's synced has been sent + // to SF + incStrong((void*)transactionCommittedCallbackThunk); + mSyncTransaction->addTransactionCommittedCallback(transactionCommittedCallbackThunk, + static_cast(this)); + if (mAcquireSingleBuffer) { mSyncTransaction = nullptr; } -- cgit v1.2.3-59-g8ed1b From 7891e96d2b87e5a140d1dd8d069dd8c834720e6a Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 11 Nov 2021 12:07:21 -0800 Subject: SF: Add continuous transaction tracing Add the ability to capture all incoming transactions into a ring buffer. Capture transactions as the come in through the binder thread. On the main thread push committed transactions to the tracing thread which will then add to the buffer and purge older entries as the buffer gets filled. Also introduce a new flag to enable transaction tracing (disabled by default). Test: presubmit Bug: 200284593 Change-Id: I90dd0fa4f89f68cfc7b7922ecd0bba4adab8d7a4 --- services/surfaceflinger/Android.bp | 1 + services/surfaceflinger/SurfaceFlinger.cpp | 60 ++++-- services/surfaceflinger/SurfaceFlinger.h | 15 +- services/surfaceflinger/Tracing/RingBuffer.h | 18 +- .../surfaceflinger/Tracing/TransactionTracing.cpp | 203 +++++++++++++++++++++ .../surfaceflinger/Tracing/TransactionTracing.h | 107 +++++++++++ services/surfaceflinger/tests/unittests/Android.bp | 1 + .../tests/unittests/TestableSurfaceFlinger.h | 2 +- .../tests/unittests/TransactionTracingTest.cpp | 138 ++++++++++++++ 9 files changed, 520 insertions(+), 25 deletions(-) create mode 100644 services/surfaceflinger/Tracing/TransactionTracing.cpp create mode 100644 services/surfaceflinger/Tracing/TransactionTracing.h create mode 100644 services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index fb42cc02eb..10ab3b491e 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -202,6 +202,7 @@ filegroup { "SurfaceFlingerDefaultFactory.cpp", "SurfaceInterceptor.cpp", "Tracing/LayerTracing.cpp", + "Tracing/TransactionTracing.cpp", "Tracing/TransactionProtoParser.cpp", "TransactionCallbackInvoker.cpp", "TunnelModeEnabledReporter.cpp", diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 93f8406319..7a8968be19 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -357,10 +357,11 @@ bool callingThreadHasRotateSurfaceFlingerAccess() { SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) : mFactory(factory), + mPid(getpid()), mInterceptor(mFactory.createSurfaceInterceptor()), mTimeStats(std::make_shared()), mFrameTracer(mFactory.createFrameTracer()), - mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, getpid())), + mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, mPid)), mCompositionEngine(mFactory.createCompositionEngine()), mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)), mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()), @@ -489,6 +490,11 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI enableSdrDimming = property_get_bool("debug.sf.enable_sdr_dimming", enable_sdr_dimming(false)); enableLatchUnsignaledConfig = getLatchUnsignaledConfig(); + + mTransactionTracingEnabled = property_get_bool("debug.sf.enable_transaction_tracing", false); + if (mTransactionTracingEnabled) { + mTransactionTracing.enable(); + } } LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() { @@ -1946,7 +1952,7 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected } if (mTracingEnabledChanged) { - mTracingEnabled = mLayerTracing.isEnabled(); + mLayerTracingEnabled = mLayerTracing.isEnabled(); mTracingEnabledChanged = false; } @@ -1964,7 +1970,7 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected bool needsTraversal = false; if (clearTransactionFlags(eTransactionFlushNeeded)) { - needsTraversal = flushTransactionQueues(); + needsTraversal = flushTransactionQueues(vsyncId); } const bool shouldCommit = @@ -2095,7 +2101,7 @@ void SurfaceFlinger::composite(nsecs_t frameTime) { modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition); mLayersWithQueuedFrames.clear(); - if (mTracingEnabled) { + if (mLayerTracingEnabled) { // This will block and should only be used for debugging. if (mVisibleRegionsDirty) { mLayerTracing.notify("visibleRegionsDirty"); @@ -3374,10 +3380,11 @@ status_t SurfaceFlinger::addClientLayer(const sp& client, const spattachLayer(handle, lbc); } + int64_t transactionId = (((int64_t)mPid) << 32) | mUniqueTransactionId++; return setTransactionState(FrameTimelineInfo{}, states, displays, 0 /* flags */, nullptr, InputWindowCommands{}, -1 /* desiredPresentTime */, true /* isAutoTimestamp */, {}, false /* hasListenerCallbacks */, {}, - 0 /* Undefined transactionId */); + transactionId); } uint32_t SurfaceFlinger::getTransactionFlags() const { @@ -3400,7 +3407,7 @@ uint32_t SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule return old; } -bool SurfaceFlinger::flushTransactionQueues() { +bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { // to prevent onHandleDestroyed from being called while the lock is held, // we must keep a copy of the transactions (specifically the composer // states) around outside the scope of the lock @@ -3486,12 +3493,13 @@ bool SurfaceFlinger::flushTransactionQueues() { ATRACE_INT("TransactionQueue", mTransactionQueue.size()); } - return applyTransactions(transactions); + return applyTransactions(transactions, vsyncId); } } } -bool SurfaceFlinger::applyTransactions(std::vector& transactions) { +bool SurfaceFlinger::applyTransactions(std::vector& transactions, + int64_t vsyncId) { bool needsTraversal = false; // Now apply all transactions. for (const auto& transaction : transactions) { @@ -3509,6 +3517,10 @@ bool SurfaceFlinger::applyTransactions(std::vector& transactio std::move(transaction.transactionCommittedSignal)); } } + + if (mTransactionTracingEnabled) { + mTransactionTracing.addCommittedTransactions(transactions, vsyncId); + } return needsTraversal; } @@ -3762,6 +3774,10 @@ status_t SurfaceFlinger::setTransactionState( state.traverseStatesWithBuffers([&](const layer_state_t& state) { mBufferCountTracker.increment(state.surface->localBinder()); }); + + if (mTransactionTracingEnabled) { + mTransactionTracing.addQueuedTransaction(state); + } queueTransaction(state); // Check the pending state to make sure the transaction is synchronous. @@ -4448,10 +4464,12 @@ void SurfaceFlinger::onInitializeDisplays() { displays.add(d); nsecs_t now = systemTime(); + + int64_t transactionId = (((int64_t)mPid) << 32) | mUniqueTransactionId++; // It should be on the main thread, apply it directly. applyTransactionState(FrameTimelineInfo{}, state, displays, 0, mInputWindowCommands, /* desiredPresentTime */ now, true, {}, /* postTime */ now, true, false, - {}, getpid(), getuid(), 0 /* Undefined transactionId */); + {}, mPid, getuid(), transactionId); setPowerModeInternal(display, hal::PowerMode::ON); const nsecs_t vsyncPeriod = @@ -4650,8 +4668,9 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { } status_t SurfaceFlinger::dumpCritical(int fd, const DumpArgs&, bool asProto) { - if (asProto && mLayerTracing.isEnabled()) { + if (asProto) { mLayerTracing.writeToFile(); + mTransactionTracing.writeToFile(); } return doDump(fd, DumpArgs(), asProto); @@ -4848,7 +4867,6 @@ void SurfaceFlinger::dumpWideColorInfo(std::string& result) const { } LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const { - // If context is SurfaceTracing thread, mTracingLock blocks display transactions on main thread. const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); LayersProto layersProto; @@ -5049,6 +5067,8 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co */ mLayerTracing.dump(result); result.append("\n"); + mTransactionTracing.dump(result); + result.append("\n"); /* * HWC layer minidump @@ -5281,9 +5301,9 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { code == IBinder::SYSPROPS_TRANSACTION) { return OK; } - // Numbers from 1000 to 1040 are currently used for backdoors. The code + // Numbers from 1000 to 1041 are currently used for backdoors. The code // in onTransact verifies that the user is root, and has access to use SF. - if (code >= 1000 && code <= 1040) { + if (code >= 1000 && code <= 1041) { ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code); return OK; } @@ -5724,6 +5744,20 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r scheduleRepaint(); return NO_ERROR; } + case 1041: { // Transaction tracing + if (data.readInt32()) { + // Transaction tracing is always running but allow the user to temporarily + // increase the buffer when actively debugging. + mTransactionTracing.setBufferSize( + TransactionTracing::ACTIVE_TRACING_BUFFER_SIZE); + } else { + mTransactionTracing.setBufferSize( + TransactionTracing::CONTINUOUS_TRACING_BUFFER_SIZE); + mTransactionTracing.writeToFile(); + } + reply->writeInt32(NO_ERROR); + return NO_ERROR; + } } } return err; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6093be91f9..56a90d1b33 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -63,6 +63,7 @@ #include "SurfaceFlingerFactory.h" #include "TracedOrdinal.h" #include "Tracing/LayerTracing.h" +#include "Tracing/TransactionTracing.h" #include "TransactionCallbackInvoker.h" #include "TransactionState.h" @@ -711,7 +712,7 @@ private: int originPid, int originUid, uint64_t transactionId) REQUIRES(mStateLock); // flush pending transaction that was presented after desiredPresentTime. - bool flushTransactionQueues(); + bool flushTransactionQueues(int64_t vsyncId); // Returns true if there is at least one transaction that needs to be flushed bool transactionFlushNeeded(); @@ -747,7 +748,8 @@ private: bool allowedLatchUnsignaled() REQUIRES(mQueueLock, mStateLock); bool checkTransactionCanLatchUnsignaled(const TransactionState& transaction) REQUIRES(mStateLock); - bool applyTransactions(std::vector& transactions) REQUIRES(mStateLock); + bool applyTransactions(std::vector& transactions, int64_t vsyncId) + REQUIRES(mStateLock); uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock); uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands) REQUIRES(mStateLock); @@ -1082,7 +1084,7 @@ private: sp mStartPropertySetThread; surfaceflinger::Factory& mFactory; - + pid_t mPid; std::future mRenderEnginePrimeCacheFuture; // access must be protected by mStateLock @@ -1091,6 +1093,7 @@ private: std::atomic mTransactionFlags = 0; std::vector> mTransactionCommittedSignals; bool mAnimTransactionPending = false; + std::atomic mUniqueTransactionId = 1; SortedVector> mLayersPendingRemoval; // global color transform states @@ -1181,8 +1184,10 @@ private: sp mInterceptor; LayerTracing mLayerTracing{*this}; - std::mutex mTracingLock; - bool mTracingEnabled = false; + bool mLayerTracingEnabled = false; + + TransactionTracing mTransactionTracing; + bool mTransactionTracingEnabled = false; std::atomic mTracingEnabledChanged = false; const std::shared_ptr mTimeStats; diff --git a/services/surfaceflinger/Tracing/RingBuffer.h b/services/surfaceflinger/Tracing/RingBuffer.h index d0fb3f28fe..63a27869b6 100644 --- a/services/surfaceflinger/Tracing/RingBuffer.h +++ b/services/surfaceflinger/Tracing/RingBuffer.h @@ -21,8 +21,9 @@ #include #include -#include +#include #include +#include #include namespace android { @@ -57,9 +58,7 @@ public: status_t writeToFile(FileProto& fileProto, std::string filename) { ATRACE_CALL(); std::string output; - flush(fileProto); - reset(mSizeInBytes); - if (!fileProto.SerializeToString(&output)) { + if (!writeToString(fileProto, &output)) { ALOGE("Could not serialize proto."); return UNKNOWN_ERROR; } @@ -73,6 +72,13 @@ public: return NO_ERROR; } + bool writeToString(FileProto& fileProto, std::string* outString) { + ATRACE_CALL(); + flush(fileProto); + reset(mSizeInBytes); + return fileProto.SerializeToString(outString); + } + std::vector emplace(EntryProto&& proto) { std::vector replacedEntries; size_t protoSize = static_cast(proto.ByteSize()); @@ -99,8 +105,8 @@ public: const int64_t durationCount = duration.count(); base::StringAppendF(&result, " number of entries: %zu (%.2fMB / %.2fMB) duration: %" PRIi64 "ms\n", - frameCount(), float(used()) / 1024.f * 1024.f, - float(size()) / 1024.f * 1024.f, durationCount); + frameCount(), float(used()) / (1024.f * 1024.f), + float(size()) / (1024.f * 1024.f), durationCount); } private: diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp new file mode 100644 index 0000000000..758bd31563 --- /dev/null +++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp @@ -0,0 +1,203 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef LOG_TAG +#define LOG_TAG "TransactionTracing" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include +#include +#include +#include + +#include "RingBuffer.h" +#include "TransactionTracing.h" + +namespace android { + +TransactionTracing::TransactionTracing() { + mBuffer = std::make_unique< + RingBuffer>(); +} + +TransactionTracing::~TransactionTracing() = default; + +bool TransactionTracing::enable() { + std::scoped_lock lock(mTraceLock); + if (mEnabled) { + return false; + } + mBuffer->setSize(mBufferSizeInBytes); + mEnabled = true; + { + std::scoped_lock lock(mMainThreadLock); + mDone = false; + mThread = std::thread(&TransactionTracing::loop, this); + } + return true; +} + +bool TransactionTracing::disable() { + std::thread thread; + { + std::scoped_lock lock(mMainThreadLock); + mDone = true; + mTransactionsAvailableCv.notify_all(); + thread = std::move(mThread); + } + if (thread.joinable()) { + thread.join(); + } + + std::scoped_lock lock(mTraceLock); + if (!mEnabled) { + return false; + } + mEnabled = false; + + proto::TransactionTraceFile fileProto = createTraceFileProto(); + mBuffer->writeToFile(fileProto, FILE_NAME); + mQueuedTransactions.clear(); + return true; +} + +bool TransactionTracing::isEnabled() const { + std::scoped_lock lock(mTraceLock); + return mEnabled; +} + +status_t TransactionTracing::writeToFile() { + std::scoped_lock lock(mTraceLock); + if (!mEnabled) { + return STATUS_OK; + } + proto::TransactionTraceFile fileProto = createTraceFileProto(); + return mBuffer->writeToFile(fileProto, FILE_NAME); +} + +void TransactionTracing::setBufferSize(size_t bufferSizeInBytes) { + std::scoped_lock lock(mTraceLock); + mBufferSizeInBytes = bufferSizeInBytes; + mBuffer->setSize(mBufferSizeInBytes); +} + +proto::TransactionTraceFile TransactionTracing::createTraceFileProto() const { + proto::TransactionTraceFile proto; + proto.set_magic_number(uint64_t(proto::TransactionTraceFile_MagicNumber_MAGIC_NUMBER_H) << 32 | + proto::TransactionTraceFile_MagicNumber_MAGIC_NUMBER_L); + return proto; +} + +void TransactionTracing::dump(std::string& result) const { + std::scoped_lock lock(mTraceLock); + base::StringAppendF(&result, "Transaction tracing state: %s\n", + mEnabled ? "enabled" : "disabled"); + base::StringAppendF(&result, " queued transactions: %d\n", + static_cast(mQueuedTransactions.size())); + mBuffer->dump(result); +} + +void TransactionTracing::addQueuedTransaction(const TransactionState& transaction) { + std::scoped_lock lock(mTraceLock); + ATRACE_CALL(); + if (!mEnabled) { + return; + } + mQueuedTransactions[transaction.id] = + TransactionProtoParser::toProto(transaction, nullptr, nullptr); +} + +void TransactionTracing::addCommittedTransactions(std::vector& transactions, + int64_t vsyncId) { + CommittedTransactions committedTransactions; + committedTransactions.vsyncId = vsyncId; + committedTransactions.timestamp = systemTime(); + committedTransactions.transactionIds.reserve(transactions.size()); + for (const auto& transaction : transactions) { + committedTransactions.transactionIds.emplace_back(transaction.id); + } + + // Try to acquire the lock from main thread, but don't block if we cannot acquire the lock. Add + // it to pending transactions that we can collect later. + if (mMainThreadLock.try_lock()) { + // We got the lock! Collect any pending transactions and continue. + mCommittedTransactions.insert(mCommittedTransactions.end(), + std::make_move_iterator(mPendingTransactions.begin()), + std::make_move_iterator(mPendingTransactions.end())); + mPendingTransactions.clear(); + mCommittedTransactions.emplace_back(committedTransactions); + mTransactionsAvailableCv.notify_one(); + mMainThreadLock.unlock(); + } else { + mPendingTransactions.emplace_back(committedTransactions); + } +} + +void TransactionTracing::loop() { + while (true) { + std::vector committedTransactions; + { + std::unique_lock lock(mMainThreadLock); + base::ScopedLockAssertion assumeLocked(mMainThreadLock); + mTransactionsAvailableCv.wait(lock, [&]() REQUIRES(mMainThreadLock) { + return mDone || !mCommittedTransactions.empty(); + }); + if (mDone) { + mCommittedTransactions.clear(); + break; + } + committedTransactions = std::move(mCommittedTransactions); + mCommittedTransactions.clear(); + } // unlock mMainThreadLock + + addEntry(committedTransactions); + + mTransactionsAddedToBufferCv.notify_one(); + } +} + +void TransactionTracing::addEntry(const std::vector& committedTransactions) { + ATRACE_CALL(); + std::scoped_lock lock(mTraceLock); + std::vector removedEntries; + for (const CommittedTransactions& entry : committedTransactions) { + proto::TransactionTraceEntry entryProto; + entryProto.set_elapsed_realtime_nanos(entry.timestamp); + entryProto.set_vsync_id(entry.vsyncId); + entryProto.mutable_transactions()->Reserve( + static_cast(entry.transactionIds.size())); + for (const uint64_t& id : entry.transactionIds) { + auto it = mQueuedTransactions.find(id); + if (it != mQueuedTransactions.end()) { + entryProto.mutable_transactions()->Add(std::move(it->second)); + mQueuedTransactions.erase(it); + } else { + ALOGE("Could not find transaction id %" PRIu64, id); + } + } + mBuffer->emplace(std::move(entryProto)); + } +} + +void TransactionTracing::flush() { + std::unique_lock lock(mMainThreadLock); + base::ScopedLockAssertion assumeLocked(mMainThreadLock); + mTransactionsAddedToBufferCv.wait(lock, [&]() REQUIRES(mMainThreadLock) { + return mCommittedTransactions.empty(); + }); +} + +} // namespace android diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h new file mode 100644 index 0000000000..d92ab014e1 --- /dev/null +++ b/services/surfaceflinger/Tracing/TransactionTracing.h @@ -0,0 +1,107 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +#include "TransactionProtoParser.h" + +using namespace android::surfaceflinger; + +namespace android { + +template +class RingBuffer; + +class SurfaceFlinger; +class TransactionTracingTest; +/* + * Records all committed transactions into a ring bufffer. + * + * Transactions come in via the binder thread. They are serialized to proto + * and stored in a map using the transaction id as key. Main thread will + * pass the list of transaction ids that are committed every vsync and notify + * the tracing thread. The tracing thread will then wake up and add the + * committed transactions to the ring buffer. + * + * When generating SF dump state, we will flush the buffer to a file which + * will then be included in the bugreport. + * + */ +class TransactionTracing { +public: + TransactionTracing(); + ~TransactionTracing(); + + bool enable(); + bool disable(); + bool isEnabled() const; + + void addQueuedTransaction(const TransactionState&); + void addCommittedTransactions(std::vector& transactions, int64_t vsyncId); + status_t writeToFile(); + void setBufferSize(size_t bufferSizeInBytes); + void dump(std::string&) const; + static constexpr auto CONTINUOUS_TRACING_BUFFER_SIZE = 512 * 1024; + static constexpr auto ACTIVE_TRACING_BUFFER_SIZE = 100 * 1024 * 1024; + +private: + friend class TransactionTracingTest; + + static constexpr auto FILE_NAME = "/data/misc/wmtrace/transactions_trace.winscope"; + + mutable std::mutex mTraceLock; + bool mEnabled GUARDED_BY(mTraceLock) = false; + std::unique_ptr> mBuffer + GUARDED_BY(mTraceLock); + size_t mBufferSizeInBytes GUARDED_BY(mTraceLock) = CONTINUOUS_TRACING_BUFFER_SIZE; + std::unordered_map mQueuedTransactions + GUARDED_BY(mTraceLock); + + // We do not want main thread to block so main thread will try to acquire mMainThreadLock, + // otherwise will push data to temporary container. + std::mutex mMainThreadLock; + std::thread mThread GUARDED_BY(mMainThreadLock); + bool mDone GUARDED_BY(mMainThreadLock) = false; + std::condition_variable mTransactionsAvailableCv; + std::condition_variable mTransactionsAddedToBufferCv; + struct CommittedTransactions { + std::vector transactionIds; + int64_t vsyncId; + int64_t timestamp; + }; + std::vector mCommittedTransactions GUARDED_BY(mMainThreadLock); + std::vector mPendingTransactions; // only accessed by main thread + proto::TransactionTraceFile createTraceFileProto() const; + + void loop(); + void addEntry(const std::vector& committedTransactions) + EXCLUDES(mTraceLock); + + // TEST + // Wait until all the committed transactions are added to the buffer. + void flush() EXCLUDES(mMainThreadLock); +}; + +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 3dc6d8b5c1..c0d2e99794 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -93,6 +93,7 @@ cc_test { "TransactionFrameTracerTest.cpp", "TransactionProtoParserTest.cpp", "TransactionSurfaceFrameTest.cpp", + "TransactionTracingTest.cpp", "TunnelModeEnabledReporterTest.cpp", "StrongTypingTest.cpp", "VSyncDispatchTimerQueueTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 4c5789e47f..cd7c88e381 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -380,7 +380,7 @@ public: listenerCallbacks, transactionId); } - auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(); }; + auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(0); }; auto onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { return mFlinger->onTransact(code, data, reply, flags); diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp new file mode 100644 index 0000000000..2afa68ab68 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp @@ -0,0 +1,138 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +#include "Tracing/RingBuffer.h" +#include "Tracing/TransactionTracing.h" + +using namespace android::surfaceflinger; + +namespace android { + +class TransactionTracingTest : public testing::Test { +protected: + std::unique_ptr mTracing; + + void SetUp() override { mTracing = std::make_unique(); } + + void TearDown() override { mTracing.reset(); } + + auto getCommittedTransactions() { + std::scoped_lock lock(mTracing->mMainThreadLock); + return mTracing->mCommittedTransactions; + } + + auto getQueuedTransactions() { + std::scoped_lock lock(mTracing->mTraceLock); + return mTracing->mQueuedTransactions; + } + + auto getUsedBufferSize() { + std::scoped_lock lock(mTracing->mTraceLock); + return mTracing->mBuffer->used(); + } + + auto flush() { return mTracing->flush(); } + + auto bufferFront() { + std::scoped_lock lock(mTracing->mTraceLock); + return mTracing->mBuffer->front(); + } + + bool threadIsJoinable() { + std::scoped_lock lock(mTracing->mMainThreadLock); + return mTracing->mThread.joinable(); + } + + std::string writeToString() { + std::scoped_lock lock(mTracing->mTraceLock); + std::string output; + proto::TransactionTraceFile fileProto = mTracing->createTraceFileProto(); + mTracing->mBuffer->writeToString(fileProto, &output); + return output; + } + + // Test that we clean up the tracing thread and free any memory allocated. + void verifyDisabledTracingState() { + EXPECT_FALSE(mTracing->isEnabled()); + EXPECT_FALSE(threadIsJoinable()); + EXPECT_EQ(getCommittedTransactions().size(), 0u); + EXPECT_EQ(getQueuedTransactions().size(), 0u); + EXPECT_EQ(getUsedBufferSize(), 0u); + } + + void verifyEntry(const proto::TransactionTraceEntry& actualProto, + const std::vector expectedTransactions, + int64_t expectedVsyncId) { + EXPECT_EQ(actualProto.vsync_id(), expectedVsyncId); + EXPECT_EQ(actualProto.transactions().size(), + static_cast(expectedTransactions.size())); + for (uint32_t i = 0; i < expectedTransactions.size(); i++) { + EXPECT_EQ(actualProto.transactions(static_cast(i)).pid(), + expectedTransactions[i].originPid); + } + } +}; + +TEST_F(TransactionTracingTest, enable) { + EXPECT_FALSE(mTracing->isEnabled()); + mTracing->enable(); + EXPECT_TRUE(mTracing->isEnabled()); + mTracing->disable(); + verifyDisabledTracingState(); +} + +TEST_F(TransactionTracingTest, addTransactions) { + mTracing->enable(); + std::vector transactions; + transactions.reserve(100); + for (uint64_t i = 0; i < 100; i++) { + TransactionState transaction; + transaction.id = i; + transaction.originPid = static_cast(i); + transactions.emplace_back(transaction); + mTracing->addQueuedTransaction(transaction); + } + + // Split incoming transactions into two and commit them in reverse order to test out of order + // commits. + std::vector firstTransactionSet = + std::vector(transactions.begin() + 50, transactions.end()); + int64_t firstTransactionSetVsyncId = 42; + mTracing->addCommittedTransactions(firstTransactionSet, firstTransactionSetVsyncId); + + int64_t secondTransactionSetVsyncId = 43; + std::vector secondTransactionSet = + std::vector(transactions.begin(), transactions.begin() + 50); + mTracing->addCommittedTransactions(secondTransactionSet, secondTransactionSetVsyncId); + flush(); + + std::string protoString = writeToString(); + proto::TransactionTraceFile proto; + proto.ParseFromString(protoString); + EXPECT_EQ(proto.entry().size(), 2); + verifyEntry(proto.entry(0), firstTransactionSet, firstTransactionSetVsyncId); + verifyEntry(proto.entry(1), secondTransactionSet, secondTransactionSetVsyncId); + + mTracing->disable(); + verifyDisabledTracingState(); +} + +} // namespace android -- cgit v1.2.3-59-g8ed1b From f12f2f7aadfe9b9440115a5874d64de570f4265e Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 17 Nov 2021 17:49:45 -0800 Subject: Convert connection status to enum class This allows us to print the value using ftl::enum_string Bug: 206861133 Test: printed the connection status locally Change-Id: I1042c4ab785eae2d703cf5e6e3c0f7c50d6be6c1 --- services/inputflinger/dispatcher/Connection.cpp | 15 +--------- services/inputflinger/dispatcher/Connection.h | 12 ++++---- services/inputflinger/dispatcher/Entry.cpp | 5 ++-- .../inputflinger/dispatcher/InputDispatcher.cpp | 32 ++++++++++++---------- 4 files changed, 27 insertions(+), 37 deletions(-) diff --git a/services/inputflinger/dispatcher/Connection.cpp b/services/inputflinger/dispatcher/Connection.cpp index cee9c39abd..b4497fd653 100644 --- a/services/inputflinger/dispatcher/Connection.cpp +++ b/services/inputflinger/dispatcher/Connection.cpp @@ -22,7 +22,7 @@ namespace android::inputdispatcher { Connection::Connection(const std::shared_ptr& inputChannel, bool monitor, const IdGenerator& idGenerator) - : status(STATUS_NORMAL), + : status(Status::NORMAL), inputChannel(inputChannel), monitor(monitor), inputPublisher(inputChannel), @@ -40,19 +40,6 @@ const std::string Connection::getWindowName() const { return "?"; } -const char* Connection::getStatusLabel() const { - switch (status) { - case STATUS_NORMAL: - return "NORMAL"; - case STATUS_BROKEN: - return "BROKEN"; - case STATUS_ZOMBIE: - return "ZOMBIE"; - default: - return "UNKNOWN"; - } -} - std::deque::iterator Connection::findWaitQueueEntry(uint32_t seq) { for (std::deque::iterator it = waitQueue.begin(); it != waitQueue.end(); it++) { if ((*it)->seq == seq) { diff --git a/services/inputflinger/dispatcher/Connection.h b/services/inputflinger/dispatcher/Connection.h index ba602831eb..dc6a081ff6 100644 --- a/services/inputflinger/dispatcher/Connection.h +++ b/services/inputflinger/dispatcher/Connection.h @@ -33,13 +33,16 @@ protected: virtual ~Connection(); public: - enum Status { + enum class Status { // Everything is peachy. - STATUS_NORMAL, + NORMAL, // An unrecoverable communication error has occurred. - STATUS_BROKEN, + BROKEN, // The input channel has been unregistered. - STATUS_ZOMBIE + ZOMBIE, + + ftl_first = NORMAL, + ftl_last = ZOMBIE, }; Status status; @@ -66,7 +69,6 @@ public: inline const std::string getInputChannelName() const { return inputChannel->getName(); } const std::string getWindowName() const; - const char* getStatusLabel() const; std::deque::iterator findWaitQueueEntry(uint32_t seq); }; diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index 1674afd02e..f6bb6a63a7 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -289,11 +289,10 @@ SensorEntry::~SensorEntry() {} std::string SensorEntry::getDescription() const { std::string msg; - std::string sensorTypeStr(ftl::enum_name(sensorType).value_or("?")); msg += StringPrintf("SensorEntry(deviceId=%d, source=%s, sensorType=%s, " "accuracy=0x%08x, hwTimestamp=%" PRId64, - deviceId, inputEventSourceToString(source).c_str(), sensorTypeStr.c_str(), - accuracy, hwTimestamp); + deviceId, inputEventSourceToString(source).c_str(), + ftl::enum_string(sensorType).c_str(), accuracy, hwTimestamp); if (!GetBoolProperty("ro.debuggable", false)) { for (size_t i = 0; i < values.size(); i++) { diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 7f68d1b8b1..eb9e2d8a31 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -1749,7 +1749,7 @@ void InputDispatcher::cancelEventsForAnrLocked(const sp& connection) // pile up. ALOGW("Canceling events for %s because it is unresponsive", connection->inputChannel->getName().c_str()); - if (connection->status == Connection::STATUS_NORMAL) { + if (connection->status == Connection::Status::NORMAL) { CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, "application not responding"); synthesizeCancelationEventsForConnectionLocked(connection, options); @@ -2825,10 +2825,11 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, // Skip this event if the connection status is not normal. // We don't want to enqueue additional outbound events if the connection is broken. - if (connection->status != Connection::STATUS_NORMAL) { + if (connection->status != Connection::Status::NORMAL) { if (DEBUG_DISPATCH_CYCLE) { ALOGD("channel '%s' ~ Dropping event because the channel status is %s", - connection->getInputChannelName().c_str(), connection->getStatusLabel()); + connection->getInputChannelName().c_str(), + ftl::enum_string(connection->status).c_str()); } return; } @@ -3142,7 +3143,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, ALOGD("channel '%s' ~ startDispatchCycle", connection->getInputChannelName().c_str()); } - while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) { + while (connection->status == Connection::Status::NORMAL && !connection->outboundQueue.empty()) { DispatchEntry* dispatchEntry = connection->outboundQueue.front(); dispatchEntry->deliveryTime = currentTime; const std::chrono::nanoseconds timeout = @@ -3363,8 +3364,8 @@ void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, connection->getInputChannelName().c_str(), seq, toString(handled)); } - if (connection->status == Connection::STATUS_BROKEN || - connection->status == Connection::STATUS_ZOMBIE) { + if (connection->status == Connection::Status::BROKEN || + connection->status == Connection::Status::ZOMBIE) { return; } @@ -3391,8 +3392,8 @@ void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, // The connection appears to be unrecoverably broken. // Ignore already broken or zombie connections. - if (connection->status == Connection::STATUS_NORMAL) { - connection->status = Connection::STATUS_BROKEN; + if (connection->status == Connection::Status::NORMAL) { + connection->status = Connection::Status::BROKEN; if (notify) { // Notify other system components. @@ -3400,7 +3401,7 @@ void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, connection->getInputChannelName().c_str()); auto command = [this, connection]() REQUIRES(mLock) { - if (connection->status == Connection::STATUS_ZOMBIE) return; + if (connection->status == Connection::Status::ZOMBIE) return; scoped_unlock unlock(mLock); mPolicy->notifyInputChannelBroken(connection->inputChannel->getConnectionToken()); }; @@ -3536,7 +3537,7 @@ void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked( void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( const sp& connection, const CancelationOptions& options) { - if (connection->status == Connection::STATUS_BROKEN) { + if (connection->status == Connection::Status::BROKEN) { return; } @@ -3609,7 +3610,7 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( const sp& connection) { - if (connection->status == Connection::STATUS_BROKEN) { + if (connection->status == Connection::Status::BROKEN) { return; } @@ -5286,7 +5287,8 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { "status=%s, monitor=%s, responsive=%s\n", connection->inputChannel->getFd().get(), connection->getInputChannelName().c_str(), - connection->getWindowName().c_str(), connection->getStatusLabel(), + connection->getWindowName().c_str(), + ftl::enum_string(connection->status).c_str(), toString(connection->monitor), toString(connection->responsive)); if (!connection->outboundQueue.empty()) { @@ -5459,7 +5461,7 @@ status_t InputDispatcher::removeInputChannelLocked(const sp& connection nsecs_t currentTime = now(); abortBrokenDispatchCycleLocked(currentTime, connection, notify); - connection->status = Connection::STATUS_ZOMBIE; + connection->status = Connection::Status::ZOMBIE; return OK; } @@ -5678,7 +5680,7 @@ void InputDispatcher::doDispatchCycleFinishedCommand(nsecs_t finishTime, } } traceWaitQueueLength(*connection); - if (restartEvent && connection->status == Connection::STATUS_NORMAL) { + if (restartEvent && connection->status == Connection::Status::NORMAL) { connection->outboundQueue.push_front(dispatchEntry); traceOutboundQueueLength(*connection); } else { @@ -5976,7 +5978,7 @@ bool InputDispatcher::afterKeyEventLockedInterruptable(const sp& con mLock.lock(); - if (connection->status != Connection::STATUS_NORMAL) { + if (connection->status != Connection::Status::NORMAL) { connection->inputState.removeFallbackKey(originalKeyCode); return false; } -- cgit v1.2.3-59-g8ed1b From 7aa3e9498036bd58e5e73f3808baa93447e267fb Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Thu, 18 Nov 2021 09:49:11 -0800 Subject: Notify policy about broken input channels The InputDispatcherPolicyInterface contains a callback for 'notifyInputChannelBroken'. Looking at the implementation of the policy for this callback, inside InputManagerCallback.java, the intent of this callback is to call windowState.removeIfPossible(). In other words, try to remove the window when the input channel is broken. In the input code, this could be triggered in 3 different ways: 1) pipe is full (WOULD_BLOCK), but the wait queue is empty 2) can't write to socket, but the error is other than 'WOULD_BLOCK' 3) 'removeInputChannelLocked' is called The first two cases don't really happen in practice. The last case can happen when the app closes the socket, but the window still remains on the screen (maybe temporarily). It turns out, before this patch, the policy was never getting notified for the case 3) either. That means, this API has not been called in a very long time (> 7 years from brief look through the code history). It was never getting called because the policy callback is skipped if the input connection is marked as 'zombie'. However, in 'removeInputChannelLocked', the connection is marked as 'zombie' as soon as the notifyInputChannelBroken command is queued. So in practice, the connection is already zombie before the policy notification can happen. In this CL, we remove the check for the connection being zombie. We will always notify, since once an fd is closed, there's no way to recover from that. If this CL causes breakages because this code path is now going to be triggered, we should either fix the WM implementation of this callback, or we should just remove this policy callback altogether. Bug: 206861133 Test: atest inputflinger_tests Change-Id: Iaaf5e9c3a2681d7afa444913bd6f2686c413e7df --- .../inputflinger/dispatcher/InputDispatcher.cpp | 1 - .../inputflinger/tests/InputDispatcher_test.cpp | 70 ++++++++++++++++++---- 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index eb9e2d8a31..7bef77516e 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3401,7 +3401,6 @@ void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, connection->getInputChannelName().c_str()); auto command = [this, connection]() REQUIRES(mLock) { - if (connection->status == Connection::Status::ZOMBIE) return; scoped_unlock unlock(mLock); mPolicy->notifyInputChannelBroken(connection->inputChannel->getConnectionToken()); }; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 515a01e137..c5d9e66960 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -219,21 +219,21 @@ public: template T getAnrTokenLockedInterruptible(std::chrono::nanoseconds timeout, std::queue& storage, std::unique_lock& lock) REQUIRES(mLock) { - const std::chrono::time_point start = std::chrono::steady_clock::now(); - std::chrono::duration timeToWait = timeout + 100ms; // provide some slack - // If there is an ANR, Dispatcher won't be idle because there are still events // in the waitQueue that we need to check on. So we can't wait for dispatcher to be idle // before checking if ANR was called. // Since dispatcher is not guaranteed to call notifyNoFocusedWindowAnr right away, we need // to provide it some time to act. 100ms seems reasonable. - mNotifyAnr.wait_for(lock, timeToWait, - [&storage]() REQUIRES(mLock) { return !storage.empty(); }); - const std::chrono::duration waited = std::chrono::steady_clock::now() - start; - if (storage.empty()) { + std::chrono::duration timeToWait = timeout + 100ms; // provide some slack + const std::chrono::time_point start = std::chrono::steady_clock::now(); + std::optional token = + getItemFromStorageLockedInterruptible(timeToWait, storage, lock, mNotifyAnr); + if (!token.has_value()) { ADD_FAILURE() << "Did not receive the ANR callback"; return {}; } + + const std::chrono::duration waited = std::chrono::steady_clock::now() - start; // Ensure that the ANR didn't get raised too early. We can't be too strict here because // the dispatcher started counting before this function was called if (std::chrono::abs(timeout - waited) > 100ms) { @@ -243,9 +243,24 @@ public: << std::chrono::duration_cast(waited).count() << "ms instead"; } - T token = storage.front(); + return *token; + } + + template + std::optional getItemFromStorageLockedInterruptible(std::chrono::nanoseconds timeout, + std::queue& storage, + std::unique_lock& lock, + std::condition_variable& condition) + REQUIRES(mLock) { + condition.wait_for(lock, timeout, + [&storage]() REQUIRES(mLock) { return !storage.empty(); }); + if (storage.empty()) { + ADD_FAILURE() << "Did not receive the expected callback"; + return std::nullopt; + } + T item = storage.front(); storage.pop(); - return token; + return std::make_optional(item); } void assertNotifyAnrWasNotCalled() { @@ -303,6 +318,16 @@ public: mNotifyDropWindowWasCalled = false; } + void assertNotifyInputChannelBrokenWasCalled(const sp& token) { + std::unique_lock lock(mLock); + base::ScopedLockAssertion assumeLocked(mLock); + std::optional> receivedToken = + getItemFromStorageLockedInterruptible(100ms, mBrokenInputChannels, lock, + mNotifyInputChannelBroken); + ASSERT_TRUE(receivedToken.has_value()); + ASSERT_EQ(token, *receivedToken); + } + private: std::mutex mLock; std::unique_ptr mFilteredEvent GUARDED_BY(mLock); @@ -321,6 +346,8 @@ private: std::queue mAnrMonitorPids GUARDED_BY(mLock); std::queue mResponsiveMonitorPids GUARDED_BY(mLock); std::condition_variable mNotifyAnr; + std::queue> mBrokenInputChannels GUARDED_BY(mLock); + std::condition_variable mNotifyInputChannelBroken; sp mDropTargetWindowToken GUARDED_BY(mLock); bool mNotifyDropWindowWasCalled GUARDED_BY(mLock) = false; @@ -361,7 +388,11 @@ private: mNotifyAnr.notify_all(); } - void notifyInputChannelBroken(const sp&) override {} + void notifyInputChannelBroken(const sp& connectionToken) override { + std::scoped_lock lock(mLock); + mBrokenInputChannels.push(connectionToken); + mNotifyInputChannelBroken.notify_all(); + } void notifyFocusChanged(const sp&, const sp&) override {} @@ -1175,6 +1206,8 @@ public: mInfo.ownerUid = ownerUid; } + void destroyReceiver() { mInputReceiver = nullptr; } + private: const std::string mName; std::unique_ptr mInputReceiver; @@ -1438,6 +1471,23 @@ static NotifyPointerCaptureChangedArgs generatePointerCaptureChangedArgs( return NotifyPointerCaptureChangedArgs(/* id */ 0, systemTime(SYSTEM_TIME_MONOTONIC), request); } +/** + * When a window unexpectedly disposes of its input channel, policy should be notified about the + * broken channel. + */ +TEST_F(InputDispatcherTest, WhenInputChannelBreaks_PolicyIsNotified) { + std::shared_ptr application = std::make_shared(); + sp window = + new FakeWindowHandle(application, mDispatcher, "Window that breaks its input channel", + ADISPLAY_ID_DEFAULT); + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + + // Window closes its channel, but the window remains. + window->destroyReceiver(); + mFakePolicy->assertNotifyInputChannelBrokenWasCalled(window->getInfo()->token); +} + TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) { std::shared_ptr application = std::make_shared(); sp window = -- cgit v1.2.3-59-g8ed1b From 2b03097e1d214cda46a72cd236ca31c75492a25a Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Thu, 18 Nov 2021 10:01:27 -0800 Subject: Ensure wallpaper connection is valid before canceling its events The InputDispatcher function 'synthesizeCancelationEventsForConnectionLocked' expects non-null connection. Ideally, we would refactor this function to receive Connection&. However, this connection needs to be passed to other functions called within, so for simplicity, we are keeping the incoming parameter as sp. That means that the called must ensure that the connection is not null. Fix the previous wallpaper CL by checking if the connection is null. Bug: 206651192 Test: atest inputflinger_tests Change-Id: Id6d9235144606a629dfbd2614e211412def1a68e --- .../inputflinger/dispatcher/InputDispatcher.cpp | 6 ++- .../inputflinger/tests/InputDispatcher_test.cpp | 47 ++++++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 7bef77516e..d5d906b335 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -4689,8 +4689,10 @@ void InputDispatcher::setInputWindowsLocked( if (wallpaper != nullptr) { sp wallpaperConnection = getConnectionLocked(wallpaper->getToken()); - synthesizeCancelationEventsForConnectionLocked(wallpaperConnection, - options); + if (wallpaperConnection != nullptr) { + synthesizeCancelationEventsForConnectionLocked(wallpaperConnection, + options); + } } } } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index c5d9e66960..ffacfb1b1f 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1627,6 +1627,53 @@ TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCance wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); } +/** + * Same test as WhenForegroundWindowDisappears_WallpaperTouchIsCanceled above, + * with the following differences: + * After ACTION_DOWN, Wallpaper window hangs up its channel, which forces the dispatcher to + * clean up the connection. + * This later may crash dispatcher during ACTION_CANCEL synthesis, if the dispatcher is not careful. + * Ensure that there's no crash in the dispatcher. + */ +TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) { + std::shared_ptr application = std::make_shared(); + sp foregroundWindow = + new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); + foregroundWindow->setHasWallpaper(true); + sp wallpaperWindow = + new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); + wallpaperWindow->setType(WindowInfo::Type::WALLPAPER); + constexpr int expectedWallpaperFlags = + AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}}); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 200})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + // Both foreground window and its wallpaper should receive the touch down + foregroundWindow->consumeMotionDown(); + wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {110, 200})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + foregroundWindow->consumeMotionMove(); + wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + + // Wallpaper closes its channel, but the window remains. + wallpaperWindow->destroyReceiver(); + mFakePolicy->assertNotifyInputChannelBrokenWasCalled(wallpaperWindow->getInfo()->token); + + // Now the foreground window goes away, but the wallpaper stays, even though its channel + // is no longer valid. + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wallpaperWindow}}}); + foregroundWindow->consumeMotionCancel(); +} + /** * A single window that receives touch (on top), and a wallpaper window underneath it. * The top window gets a multitouch gesture. -- cgit v1.2.3-59-g8ed1b From 85b2bdfe6049541049ebe2f5aa56d51e49ca52fb Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Wed, 3 Nov 2021 14:31:21 +0100 Subject: SF: Rename functions related to mode switching This change renames several function in SF in order to increase readibility. * performSetActiveMode --> setActiveModeInHwcIfNeeded * setActiveModeInternal --> updateInternalStateWithChangedMode * setActiveMode --> setActiveModeFromBackdoor This CL doesn't change behaviour. Bug: 190982486 Test: m Change-Id: I2723f66302016ffc196530f2000fce4a44524fb4 --- services/surfaceflinger/SurfaceFlinger.cpp | 16 +++++++--------- services/surfaceflinger/SurfaceFlinger.h | 6 +++--- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 45e0a3f616..095d5a883e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1102,7 +1102,7 @@ void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) { } } -status_t SurfaceFlinger::setActiveMode(const sp& displayToken, int modeId) { +status_t SurfaceFlinger::setActiveModeFromBackdoor(const sp& displayToken, int modeId) { ATRACE_CALL(); if (!displayToken) { @@ -1143,7 +1143,7 @@ status_t SurfaceFlinger::setActiveMode(const sp& displayToken, int mode return future.get(); } -void SurfaceFlinger::setActiveModeInternal() { +void SurfaceFlinger::updateInternalStateWithChangedMode() { ATRACE_CALL(); const auto display = getDefaultDisplayDeviceLocked(); @@ -1198,9 +1198,8 @@ void SurfaceFlinger::desiredActiveModeChangeDone(const sp& displa updatePhaseConfiguration(refreshRate); } -void SurfaceFlinger::performSetActiveMode() { +void SurfaceFlinger::setActiveModeInHwcIfNeeded() { ATRACE_CALL(); - ALOGV("%s", __FUNCTION__); for (const auto& iter : mDisplays) { const auto& display = iter.second; @@ -1235,8 +1234,7 @@ void SurfaceFlinger::performSetActiveMode() { to_string(display->getId()).c_str()); if (display->getActiveMode()->getId() == desiredActiveMode->mode->getId()) { - // display is not valid or we are already in the requested mode - // on both cases there is nothing left to do + // we are already in the requested mode, there is nothing left to do desiredActiveModeChangeDone(display); continue; } @@ -1935,7 +1933,7 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected // We received the present fence from the HWC, so we assume it successfully updated // the mode, hence we update SF. mSetActiveModePending = false; - ON_MAIN_THREAD(setActiveModeInternal()); + ON_MAIN_THREAD(updateInternalStateWithChangedMode()); } if (framePending) { @@ -2002,7 +2000,7 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected mScheduler->chooseRefreshRateForContent(); } - ON_MAIN_THREAD(performSetActiveMode()); + ON_MAIN_THREAD(setActiveModeInHwcIfNeeded()); updateCursorAsync(); updateInputFlinger(); @@ -5611,7 +5609,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r }(); mDebugDisplayModeSetByBackdoor = false; - const status_t result = setActiveMode(display, modeId); + const status_t result = setActiveModeFromBackdoor(display, modeId); mDebugDisplayModeSetByBackdoor = result == NO_ERROR; return result; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6093be91f9..53cbcabdbd 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -659,13 +659,13 @@ private: 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 setActiveMode(const sp& displayToken, int id); + status_t setActiveModeFromBackdoor(const sp& displayToken, int id); // Once HWC has returned the present fence, this sets the active mode and a new refresh // rate in SF. - void setActiveModeInternal() REQUIRES(mStateLock); + void updateInternalStateWithChangedMode() REQUIRES(mStateLock); // Calls to setActiveMode on the main thread if there is a pending mode change // that needs to be applied. - void performSetActiveMode() REQUIRES(mStateLock); + void setActiveModeInHwcIfNeeded() REQUIRES(mStateLock); void clearDesiredActiveModeState(const sp&) REQUIRES(mStateLock); // Called when active mode is no longer is progress void desiredActiveModeChangeDone(const sp&) REQUIRES(mStateLock); -- cgit v1.2.3-59-g8ed1b From 4049b53017f5cfdac2c1afecc6d7b4571dd4dce6 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 15 Oct 2021 20:59:33 -0700 Subject: Add CPU implementation for tone-mapping curves. This allows for library implementations that do not wish to place a dependency on a GPU driver to build a lookup table. A secondary use-case, which is included in this CL, is to allow for building unit-tests for checking the validity of the tone-mapping curve. See the newly added test in RenderEngineTest which validates the PQ tone-mapping curve by checking grey values. Bug: 200310159 Test: librenderengine_test Change-Id: Ic765485c22c53b4dc58a2bc8db42fd51ac7f2eea --- libs/renderengine/skia/filters/LinearEffect.cpp | 2 +- libs/renderengine/tests/RenderEngineTest.cpp | 217 ++++++++++++++++++-- libs/tonemap/Android.bp | 6 + libs/tonemap/include/tonemap/tonemap.h | 18 +- libs/tonemap/tests/Android.bp | 1 + libs/tonemap/tonemap.cpp | 258 +++++++++++++++++++++++- 6 files changed, 477 insertions(+), 25 deletions(-) diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp index c3a5a60e13..b43a3aa5ce 100644 --- a/libs/renderengine/skia/filters/LinearEffect.cpp +++ b/libs/renderengine/skia/filters/LinearEffect.cpp @@ -104,7 +104,7 @@ static void generateXYZTransforms(SkString& shader) { uniform float4x4 in_rgbToXyz; uniform float4x4 in_xyzToRgb; float3 ToXYZ(float3 rgb) { - return clamp((in_rgbToXyz * float4(rgb, 1.0)).rgb, 0.0, 1.0); + return (in_rgbToXyz * float4(rgb, 1.0)).rgb; } float3 ToRGB(float3 xyz) { diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index c2c05f41b7..5bc08ac089 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -27,6 +27,9 @@ #include #include #include +#include +#include +#include #include #include @@ -282,6 +285,13 @@ public: void expectBufferColor(const Rect& rect, uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint8_t tolerance = 0) { + auto generator = [=](Point) { return ubyte4(r, g, b, a); }; + expectBufferColor(rect, generator, tolerance); + } + + using ColorGenerator = std::function; + + void expectBufferColor(const Rect& rect, ColorGenerator generator, uint8_t tolerance = 0) { auto colorCompare = [tolerance](const uint8_t* colorA, const uint8_t* colorB) { auto colorBitCompare = [tolerance](uint8_t a, uint8_t b) { uint8_t tmp = a >= b ? a - b : b - a; @@ -290,10 +300,10 @@ public: return std::equal(colorA, colorA + 4, colorB, colorBitCompare); }; - expectBufferColor(rect, r, g, b, a, colorCompare); + expectBufferColor(rect, generator, colorCompare); } - void expectBufferColor(const Rect& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a, + void expectBufferColor(const Rect& region, ColorGenerator generator, std::function colorCompare) { uint8_t* pixels; mBuffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, @@ -304,19 +314,22 @@ public: const uint8_t* src = pixels + (mBuffer->getBuffer()->getStride() * (region.top + j) + region.left) * 4; for (int32_t i = 0; i < region.getWidth(); i++) { - const uint8_t expected[4] = {r, g, b, a}; - bool equal = colorCompare(src, expected); - EXPECT_TRUE(equal) + const auto location = Point(region.left + i, region.top + j); + const ubyte4 colors = generator(location); + const uint8_t expected[4] = {colors.r, colors.g, colors.b, colors.a}; + bool colorMatches = colorCompare(src, expected); + EXPECT_TRUE(colorMatches) << GetParam()->name().c_str() << ": " - << "pixel @ (" << region.left + i << ", " << region.top + j << "): " - << "expected (" << static_cast(r) << ", " - << static_cast(g) << ", " << static_cast(b) << ", " - << static_cast(a) << "), " + << "pixel @ (" << location.x << ", " << location.y << "): " + << "expected (" << static_cast(colors.r) << ", " + << static_cast(colors.g) << ", " + << static_cast(colors.b) << ", " + << static_cast(colors.a) << "), " << "got (" << static_cast(src[0]) << ", " << static_cast(src[1]) << ", " << static_cast(src[2]) << ", " << static_cast(src[3]) << ")"; src += 4; - if (!equal && ++fails >= maxFails) { + if (!colorMatches && ++fails >= maxFails) { break; } } @@ -328,10 +341,11 @@ public: } void expectAlpha(const Rect& rect, uint8_t a) { + auto generator = [=](Point) { return ubyte4(0, 0, 0, a); }; auto colorCompare = [](const uint8_t* colorA, const uint8_t* colorB) { return colorA[3] == colorB[3]; }; - expectBufferColor(rect, 0.0f /* r */, 0.0f /*g */, 0.0f /* b */, a, colorCompare); + expectBufferColor(rect, generator, colorCompare); } void expectShadowColor(const renderengine::LayerSettings& castingLayer, @@ -1099,7 +1113,7 @@ void RenderEngineTest::fillRedBufferTextureTransform() { layer.source.buffer.buffer = buf; layer.source.buffer.textureName = texName; // Transform coordinates to only be inside the red quadrant. - layer.source.buffer.textureTransform = mat4::scale(vec4(0.2, 0.2, 1, 1)); + layer.source.buffer.textureTransform = mat4::scale(vec4(0.2f, 0.2f, 1.f, 1.f)); layer.alpha = 1.0f; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); @@ -1281,7 +1295,8 @@ TEST_P(RenderEngineTest, drawLayers_withoutBuffers_withColorTransform) { settings.clip = fullscreenRect(); // 255, 255, 255, 255 is full opaque white. - const ubyte4 backgroundColor(255.f, 255.f, 255.f, 255.f); + const ubyte4 backgroundColor(static_cast(255), static_cast(255), + static_cast(255), static_cast(255)); // Create layer with given color. renderengine::LayerSettings bgLayer; bgLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1615,7 +1630,8 @@ TEST_P(RenderEngineTest, drawLayers_fillBuffer_withoutPremultiplyingAlpha) { TEST_P(RenderEngineTest, drawLayers_fillShadow_castsWithoutCasterLayer) { initializeRenderEngine(); - const ubyte4 backgroundColor(255, 255, 255, 255); + const ubyte4 backgroundColor(static_cast(255), static_cast(255), + static_cast(255), static_cast(255)); const float shadowLength = 5.0f; Rect casterBounds(DEFAULT_DISPLAY_WIDTH / 3.0f, DEFAULT_DISPLAY_HEIGHT / 3.0f); casterBounds.offsetBy(shadowLength + 1, shadowLength + 1); @@ -1630,8 +1646,10 @@ TEST_P(RenderEngineTest, drawLayers_fillShadow_castsWithoutCasterLayer) { TEST_P(RenderEngineTest, drawLayers_fillShadow_casterLayerMinSize) { initializeRenderEngine(); - const ubyte4 casterColor(255, 0, 0, 255); - const ubyte4 backgroundColor(255, 255, 255, 255); + const ubyte4 casterColor(static_cast(255), static_cast(0), + static_cast(0), static_cast(255)); + const ubyte4 backgroundColor(static_cast(255), static_cast(255), + static_cast(255), static_cast(255)); const float shadowLength = 5.0f; Rect casterBounds(1, 1); casterBounds.offsetBy(shadowLength + 1, shadowLength + 1); @@ -1649,8 +1667,10 @@ TEST_P(RenderEngineTest, drawLayers_fillShadow_casterLayerMinSize) { TEST_P(RenderEngineTest, drawLayers_fillShadow_casterColorLayer) { initializeRenderEngine(); - const ubyte4 casterColor(255, 0, 0, 255); - const ubyte4 backgroundColor(255, 255, 255, 255); + const ubyte4 casterColor(static_cast(255), static_cast(0), + static_cast(0), static_cast(255)); + const ubyte4 backgroundColor(static_cast(255), static_cast(255), + static_cast(255), static_cast(255)); const float shadowLength = 5.0f; Rect casterBounds(DEFAULT_DISPLAY_WIDTH / 3.0f, DEFAULT_DISPLAY_HEIGHT / 3.0f); casterBounds.offsetBy(shadowLength + 1, shadowLength + 1); @@ -1669,8 +1689,10 @@ TEST_P(RenderEngineTest, drawLayers_fillShadow_casterColorLayer) { TEST_P(RenderEngineTest, drawLayers_fillShadow_casterOpaqueBufferLayer) { initializeRenderEngine(); - const ubyte4 casterColor(255, 0, 0, 255); - const ubyte4 backgroundColor(255, 255, 255, 255); + const ubyte4 casterColor(static_cast(255), static_cast(0), + static_cast(0), static_cast(255)); + const ubyte4 backgroundColor(static_cast(255), static_cast(255), + static_cast(255), static_cast(255)); const float shadowLength = 5.0f; Rect casterBounds(DEFAULT_DISPLAY_WIDTH / 3.0f, DEFAULT_DISPLAY_HEIGHT / 3.0f); casterBounds.offsetBy(shadowLength + 1, shadowLength + 1); @@ -1690,8 +1712,10 @@ TEST_P(RenderEngineTest, drawLayers_fillShadow_casterOpaqueBufferLayer) { TEST_P(RenderEngineTest, drawLayers_fillShadow_casterWithRoundedCorner) { initializeRenderEngine(); - const ubyte4 casterColor(255, 0, 0, 255); - const ubyte4 backgroundColor(255, 255, 255, 255); + const ubyte4 casterColor(static_cast(255), static_cast(0), + static_cast(0), static_cast(255)); + const ubyte4 backgroundColor(static_cast(255), static_cast(255), + static_cast(255), static_cast(255)); const float shadowLength = 5.0f; Rect casterBounds(DEFAULT_DISPLAY_WIDTH / 3.0f, DEFAULT_DISPLAY_HEIGHT / 3.0f); casterBounds.offsetBy(shadowLength + 1, shadowLength + 1); @@ -2027,6 +2051,155 @@ TEST_P(RenderEngineTest, test_isOpaque) { expectBufferColor(rect, 0, 255, 0, 255); } } + +double EOTF_PQ(double channel) { + float m1 = (2610.0 / 4096.0) / 4.0; + float m2 = (2523.0 / 4096.0) * 128.0; + float c1 = (3424.0 / 4096.0); + float c2 = (2413.0 / 4096.0) * 32.0; + float c3 = (2392.0 / 4096.0) * 32.0; + + float tmp = std::pow(std::clamp(channel, 0.0, 1.0), 1.0 / m2); + tmp = std::fmax(tmp - c1, 0.0) / (c2 - c3 * tmp); + return std::pow(tmp, 1.0 / m1); +} + +vec3 EOTF_PQ(vec3 color) { + return vec3(EOTF_PQ(color.r), EOTF_PQ(color.g), EOTF_PQ(color.b)); +} + +double OETF_sRGB(double channel) { + return channel <= 0.0031308 ? channel * 12.92 : (pow(channel, 1.0 / 2.4) * 1.055) - 0.055; +} + +int sign(float in) { + return in >= 0.0 ? 1 : -1; +} + +vec3 OETF_sRGB(vec3 linear) { + return vec3(sign(linear.r) * OETF_sRGB(linear.r), sign(linear.g) * OETF_sRGB(linear.g), + sign(linear.b) * OETF_sRGB(linear.b)); +} + +TEST_P(RenderEngineTest, test_tonemapPQMatches) { + if (!GetParam()->useColorManagement()) { + return; + } + + if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) { + return; + } + + initializeRenderEngine(); + + constexpr int32_t kGreyLevels = 256; + + const auto rect = Rect(0, 0, kGreyLevels, 1); + const renderengine::DisplaySettings display{ + .physicalDisplay = rect, + .clip = rect, + .maxLuminance = 750.0f, + .outputDataspace = ui::Dataspace::DISPLAY_P3, + }; + + auto buf = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_RENDER | + GRALLOC_USAGE_HW_TEXTURE, + "input"), + *mRE, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); + ASSERT_EQ(0, buf->getBuffer()->initCheck()); + + { + uint8_t* pixels; + buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); + + uint8_t color = 0; + for (int32_t j = 0; j < buf->getBuffer()->getHeight(); j++) { + uint8_t* dest = pixels + (buf->getBuffer()->getStride() * j * 4); + for (int32_t i = 0; i < buf->getBuffer()->getWidth(); i++) { + dest[0] = color; + dest[1] = color; + dest[2] = color; + dest[3] = 255; + color++; + dest += 4; + } + } + buf->getBuffer()->unlock(); + } + + mBuffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_RENDER | + GRALLOC_USAGE_HW_TEXTURE, + "output"), + *mRE, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); + ASSERT_EQ(0, mBuffer->getBuffer()->initCheck()); + + const renderengine::LayerSettings layer{ + .geometry.boundaries = rect.toFloatRect(), + .source = + renderengine::PixelSource{ + .buffer = + renderengine::Buffer{ + .buffer = std::move(buf), + .usePremultipliedAlpha = true, + }, + }, + .alpha = 1.0f, + .sourceDataspace = static_cast(HAL_DATASPACE_STANDARD_BT2020 | + HAL_DATASPACE_TRANSFER_ST2084 | + HAL_DATASPACE_RANGE_FULL), + }; + + std::vector layers{layer}; + invokeDraw(display, layers); + + ColorSpace displayP3 = ColorSpace::DisplayP3(); + ColorSpace bt2020 = ColorSpace::BT2020(); + + tonemap::Metadata metadata{.displayMaxLuminance = 750.0f}; + + auto generator = [=](Point location) { + const double normColor = static_cast(location.x) / (kGreyLevels - 1); + const vec3 rgb = vec3(normColor, normColor, normColor); + + const vec3 linearRGB = EOTF_PQ(rgb); + + static constexpr float kMaxPQLuminance = 10000.f; + const vec3 xyz = bt2020.getRGBtoXYZ() * linearRGB * kMaxPQLuminance; + const double gain = + tonemap::getToneMapper() + ->lookupTonemapGain(static_cast( + HAL_DATASPACE_STANDARD_BT2020 | + HAL_DATASPACE_TRANSFER_ST2084 | + HAL_DATASPACE_RANGE_FULL), + static_cast( + ui::Dataspace::DISPLAY_P3), + linearRGB * 10000.0, xyz, metadata); + const vec3 scaledXYZ = xyz * gain / metadata.displayMaxLuminance; + + const vec3 targetRGB = OETF_sRGB(displayP3.getXYZtoRGB() * scaledXYZ) * 255; + return ubyte4(static_cast(targetRGB.r), static_cast(targetRGB.g), + static_cast(targetRGB.b), 255); + }; + + expectBufferColor(Rect(kGreyLevels, 1), generator, 2); +} } // namespace renderengine } // namespace android diff --git a/libs/tonemap/Android.bp b/libs/tonemap/Android.bp index 231a342852..5360fe2b07 100644 --- a/libs/tonemap/Android.bp +++ b/libs/tonemap/Android.bp @@ -30,7 +30,13 @@ cc_library_static { shared_libs: [ "android.hardware.graphics.common-V3-ndk", + "liblog", ], + + static_libs: [ + "libmath", + ], + srcs: [ "tonemap.cpp", ], diff --git a/libs/tonemap/include/tonemap/tonemap.h b/libs/tonemap/include/tonemap/tonemap.h index d350e160ca..bd7b72d186 100644 --- a/libs/tonemap/include/tonemap/tonemap.h +++ b/libs/tonemap/include/tonemap/tonemap.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include @@ -48,7 +49,9 @@ struct Metadata { class ToneMapper { public: virtual ~ToneMapper() {} - // Constructs a tonemap shader whose shader language is SkSL + // Constructs a tonemap shader whose shader language is SkSL, which tonemaps from an + // input whose dataspace is described by sourceDataspace, to an output whose dataspace + // is described by destinationDataspace // // The returned shader string *must* contain a function with the following signature: // float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz); @@ -94,6 +97,19 @@ public: // assume that there are predefined floats in_libtonemap_displayMaxLuminance and // in_libtonemap_inputMaxLuminance inside of the body of the tone-mapping shader. virtual std::vector generateShaderSkSLUniforms(const Metadata& metadata) = 0; + + // CPU implementation of the tonemapping gain. This must match the GPU implementation returned + // by generateTonemapGainShaderSKSL() above, with some epsilon difference to account for + // differences in hardware precision. + // + // The gain is computed assuming an input described by sourceDataspace, tonemapped to an output + // described by destinationDataspace. To compute the gain, the input colors are provided by + // linearRGB, which is the RGB colors in linear space. The colors in XYZ space are also + // provided. Metadata is also provided for helping to compute the tonemapping curve. + virtual double lookupTonemapGain( + aidl::android::hardware::graphics::common::Dataspace sourceDataspace, + aidl::android::hardware::graphics::common::Dataspace destinationDataspace, + vec3 linearRGB, vec3 xyz, const Metadata& metadata) = 0; }; // Retrieves a tonemapper instance. diff --git a/libs/tonemap/tests/Android.bp b/libs/tonemap/tests/Android.bp index e58d519224..f46f3fa27d 100644 --- a/libs/tonemap/tests/Android.bp +++ b/libs/tonemap/tests/Android.bp @@ -31,6 +31,7 @@ cc_test { "android.hardware.graphics.common-V3-ndk", ], static_libs: [ + "libmath", "libgmock", "libgtest", "libtonemap", diff --git a/libs/tonemap/tonemap.cpp b/libs/tonemap/tonemap.cpp index 2cec773eb3..c2372fe828 100644 --- a/libs/tonemap/tonemap.cpp +++ b/libs/tonemap/tonemap.cpp @@ -16,6 +16,7 @@ #include +#include #include #include #include @@ -234,9 +235,163 @@ public: .value = buildUniformValue(metadata.contentMaxLuminance)}); return uniforms; } + + double lookupTonemapGain( + aidl::android::hardware::graphics::common::Dataspace sourceDataspace, + aidl::android::hardware::graphics::common::Dataspace destinationDataspace, + vec3 /* linearRGB */, vec3 xyz, const Metadata& metadata) override { + if (xyz.y <= 0.0) { + return 1.0; + } + const int32_t sourceDataspaceInt = static_cast(sourceDataspace); + const int32_t destinationDataspaceInt = static_cast(destinationDataspace); + + double targetNits = 0.0; + switch (sourceDataspaceInt & kTransferMask) { + case kTransferST2084: + case kTransferHLG: + switch (destinationDataspaceInt & kTransferMask) { + case kTransferST2084: + targetNits = xyz.y; + break; + case kTransferHLG: + // PQ has a wider luminance range (10,000 nits vs. 1,000 nits) than HLG, so + // we'll clamp the luminance range in case we're mapping from PQ input to + // HLG output. + targetNits = std::clamp(xyz.y, 0.0f, 1000.0f); + break; + default: + // Here we're mapping from HDR to SDR content, so interpolate using a + // Hermitian polynomial onto the smaller luminance range. + + targetNits = xyz.y; + // if the max input luminance is less than what we can output then + // no tone mapping is needed as all color values will be in range. + if (metadata.contentMaxLuminance > metadata.displayMaxLuminance) { + // three control points + const double x0 = 10.0; + const double y0 = 17.0; + double x1 = metadata.displayMaxLuminance * 0.75; + double y1 = x1; + double x2 = x1 + (metadata.contentMaxLuminance - x1) / 2.0; + double y2 = y1 + (metadata.displayMaxLuminance - y1) * 0.75; + + // horizontal distances between the last three control points + double h12 = x2 - x1; + double h23 = metadata.contentMaxLuminance - x2; + // tangents at the last three control points + double m1 = (y2 - y1) / h12; + double m3 = (metadata.displayMaxLuminance - y2) / h23; + double m2 = (m1 + m3) / 2.0; + + if (targetNits < x0) { + // scale [0.0, x0] to [0.0, y0] linearly + double slope = y0 / x0; + targetNits *= slope; + } else if (targetNits < x1) { + // scale [x0, x1] to [y0, y1] linearly + double slope = (y1 - y0) / (x1 - x0); + targetNits = y0 + (targetNits - x0) * slope; + } else if (targetNits < x2) { + // scale [x1, x2] to [y1, y2] using Hermite interp + double t = (targetNits - x1) / h12; + targetNits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * + (1.0 - t) + + (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t; + } else { + // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp + double t = (targetNits - x2) / h23; + targetNits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * + (1.0 - t) + + (metadata.displayMaxLuminance * (3.0 - 2.0 * t) + + h23 * m3 * (t - 1.0)) * + t * t; + } + } + break; + } + break; + default: + // source is SDR + switch (destinationDataspaceInt & kTransferMask) { + case kTransferST2084: + case kTransferHLG: { + // Map from SDR onto an HDR output buffer + // Here we use a polynomial curve to map from [0, displayMaxLuminance] onto + // [0, maxOutLumi] which is hard-coded to be 3000 nits. + const double maxOutLumi = 3000.0; + + double x0 = 5.0; + double y0 = 2.5; + double x1 = metadata.displayMaxLuminance * 0.7; + double y1 = maxOutLumi * 0.15; + double x2 = metadata.displayMaxLuminance * 0.9; + double y2 = maxOutLumi * 0.45; + double x3 = metadata.displayMaxLuminance; + double y3 = maxOutLumi; + + double c1 = y1 / 3.0; + double c2 = y2 / 2.0; + double c3 = y3 / 1.5; + + targetNits = xyz.y; + + if (targetNits <= x0) { + // scale [0.0, x0] to [0.0, y0] linearly + double slope = y0 / x0; + targetNits *= slope; + } else if (targetNits <= x1) { + // scale [x0, x1] to [y0, y1] using a curve + double t = (targetNits - x0) / (x1 - x0); + targetNits = (1.0 - t) * (1.0 - t) * y0 + 2.0 * (1.0 - t) * t * c1 + + t * t * y1; + } else if (targetNits <= x2) { + // scale [x1, x2] to [y1, y2] using a curve + double t = (targetNits - x1) / (x2 - x1); + targetNits = (1.0 - t) * (1.0 - t) * y1 + 2.0 * (1.0 - t) * t * c2 + + t * t * y2; + } else { + // scale [x2, x3] to [y2, y3] using a curve + double t = (targetNits - x2) / (x3 - x2); + targetNits = (1.0 - t) * (1.0 - t) * y2 + 2.0 * (1.0 - t) * t * c3 + + t * t * y3; + } + } break; + default: + // For completeness, this is tone-mapping from SDR to SDR, where this is + // just a no-op. + targetNits = xyz.y; + break; + } + } + + return targetNits / xyz.y; + } }; class ToneMapper13 : public ToneMapper { +private: + double OETF_ST2084(double nits) { + nits = nits / 10000.0; + double m1 = (2610.0 / 4096.0) / 4.0; + double m2 = (2523.0 / 4096.0) * 128.0; + double c1 = (3424.0 / 4096.0); + double c2 = (2413.0 / 4096.0) * 32.0; + double c3 = (2392.0 / 4096.0) * 32.0; + + double tmp = std::pow(nits, m1); + tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp); + return std::pow(tmp, m2); + } + + double OETF_HLG(double nits) { + nits = nits / 1000.0; + const double a = 0.17883277; + const double b = 0.28466892; + const double c = 0.55991073; + return nits <= 1.0 / 12.0 ? std::sqrt(3.0 * nits) : a * std::log(12.0 * nits - b) + c; + } + public: std::string generateTonemapGainShaderSkSL( aidl::android::hardware::graphics::common::Dataspace sourceDataspace, @@ -386,6 +541,108 @@ public: .value = buildUniformValue(kContentMaxLuminance)}); return uniforms; } + + double lookupTonemapGain( + aidl::android::hardware::graphics::common::Dataspace sourceDataspace, + aidl::android::hardware::graphics::common::Dataspace destinationDataspace, + vec3 linearRGB, vec3 /* xyz */, const Metadata& metadata) override { + double maxRGB = std::max({linearRGB.r, linearRGB.g, linearRGB.b}); + + if (maxRGB <= 0.0) { + return 1.0; + } + + const int32_t sourceDataspaceInt = static_cast(sourceDataspace); + const int32_t destinationDataspaceInt = static_cast(destinationDataspace); + + double targetNits = 0.0; + switch (sourceDataspaceInt & kTransferMask) { + case kTransferST2084: + case kTransferHLG: + switch (destinationDataspaceInt & kTransferMask) { + case kTransferST2084: + targetNits = maxRGB; + break; + case kTransferHLG: + // PQ has a wider luminance range (10,000 nits vs. 1,000 nits) than HLG, so + // we'll clamp the luminance range in case we're mapping from PQ input to + // HLG output. + targetNits = std::clamp(maxRGB, 0.0, 1000.0); + break; + default: + // Here we're mapping from HDR to SDR content, so interpolate using a + // Hermitian polynomial onto the smaller luminance range. + + double maxInLumi = 4000; + double maxOutLumi = metadata.displayMaxLuminance; + + targetNits = maxRGB; + + double x1 = maxOutLumi * 0.65; + double y1 = x1; + + double x3 = maxInLumi; + double y3 = maxOutLumi; + + double x2 = x1 + (x3 - x1) * 4.0 / 17.0; + double y2 = maxOutLumi * 0.9; + + double greyNorm1 = 0.0; + double greyNorm2 = 0.0; + double greyNorm3 = 0.0; + + if ((sourceDataspaceInt & kTransferMask) == kTransferST2084) { + greyNorm1 = OETF_ST2084(x1); + greyNorm2 = OETF_ST2084(x2); + greyNorm3 = OETF_ST2084(x3); + } else if ((sourceDataspaceInt & kTransferMask) == kTransferHLG) { + greyNorm1 = OETF_HLG(x1); + greyNorm2 = OETF_HLG(x2); + greyNorm3 = OETF_HLG(x3); + } + + double slope2 = (y2 - y1) / (greyNorm2 - greyNorm1); + double slope3 = (y3 - y2) / (greyNorm3 - greyNorm2); + + if (targetNits < x1) { + break; + } + + if (targetNits > maxInLumi) { + targetNits = maxOutLumi; + break; + } + + double greyNits = 0.0; + if ((sourceDataspaceInt & kTransferMask) == kTransferST2084) { + greyNits = OETF_ST2084(targetNits); + } else if ((sourceDataspaceInt & kTransferMask) == kTransferHLG) { + greyNits = OETF_HLG(targetNits); + } + + if (greyNits <= greyNorm2) { + targetNits = (greyNits - greyNorm2) * slope2 + y2; + } else if (greyNits <= greyNorm3) { + targetNits = (greyNits - greyNorm3) * slope3 + y3; + } else { + targetNits = maxOutLumi; + } + break; + } + break; + default: + switch (destinationDataspaceInt & kTransferMask) { + case kTransferST2084: + case kTransferHLG: + default: + targetNits = maxRGB; + break; + } + break; + } + + return targetNits / maxRGB; + } }; } // namespace @@ -406,5 +663,4 @@ ToneMapper* getToneMapper() { return sToneMapper.get(); } - } // namespace android::tonemap \ No newline at end of file -- cgit v1.2.3-59-g8ed1b From dd59431d7dbf19aa4f30e7bb3bef0a724f6e5638 Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Tue, 9 Nov 2021 16:37:37 +0100 Subject: SF: Complete mode change immediately if refresh is not required Bug: 190982486 Test: atest libsurfaceflinger_unittest Change-Id: I4be91274c6570c5e9304098d5d6c3d30c41c4e6e --- services/surfaceflinger/SurfaceFlinger.cpp | 24 ++++++++++++++++++++++-- services/surfaceflinger/SurfaceFlinger.h | 3 +-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 095d5a883e..9f0ab02335 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1201,6 +1201,8 @@ void SurfaceFlinger::desiredActiveModeChangeDone(const sp& displa void SurfaceFlinger::setActiveModeInHwcIfNeeded() { ATRACE_CALL(); + std::optional displayToUpdateImmediately; + for (const auto& iter : mDisplays) { const auto& display = iter.second; if (!display || !display->isInternal()) { @@ -1265,8 +1267,26 @@ void SurfaceFlinger::setActiveModeInHwcIfNeeded() { } mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline); - // Scheduler will submit an empty frame to HWC if needed. - mSetActiveModePending = true; + if (outTimeline.refreshRequired) { + // Scheduler will submit an empty frame to HWC. + mSetActiveModePending = true; + } else { + // Updating the internal state should be done outside the loop, + // because it can recreate a DisplayDevice and modify mDisplays + // which will invalidate the iterator. + displayToUpdateImmediately = display->getPhysicalId(); + } + } + + if (displayToUpdateImmediately) { + updateInternalStateWithChangedMode(); + + const auto display = getDisplayDeviceLocked(*displayToUpdateImmediately); + const auto desiredActiveMode = display->getDesiredActiveMode(); + if (desiredActiveMode && + display->getActiveMode()->getId() == desiredActiveMode->mode->getId()) { + desiredActiveModeChangeDone(display); + } } } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 53cbcabdbd..cdec3c7516 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -660,8 +660,7 @@ private: // 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& displayToken, int id); - // Once HWC has returned the present fence, this sets the active mode and a new refresh - // rate in SF. + // 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 // that needs to be applied. -- cgit v1.2.3-59-g8ed1b From c7e9f82d3c11465fbefe809469b6d44e380d985e Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Tue, 16 Nov 2021 20:07:55 +0100 Subject: SF: Add unit test for mode switching Test: atest DisplayModeSwitchingTest Bug: 190982486 Change-Id: Ie12ab8de5d93b8a3adbb818bdda9003f4c6bbed7 --- services/surfaceflinger/tests/unittests/Android.bp | 1 + .../SurfaceFlinger_DisplayModeSwitching.cpp | 295 +++++++++++++++++++++ .../tests/unittests/TestableSurfaceFlinger.h | 49 +++- 3 files changed, 338 insertions(+), 7 deletions(-) create mode 100644 services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 3dc6d8b5c1..af635f9127 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -71,6 +71,7 @@ cc_test { "MessageQueueTest.cpp", "SurfaceFlinger_CreateDisplayTest.cpp", "SurfaceFlinger_DestroyDisplayTest.cpp", + "SurfaceFlinger_DisplayModeSwitching.cpp", "SurfaceFlinger_DisplayTransactionCommitTest.cpp", "SurfaceFlinger_GetDisplayNativePrimariesTest.cpp", "SurfaceFlinger_HotplugTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp new file mode 100644 index 0000000000..025edc2147 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp @@ -0,0 +1,295 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mock/MockEventThread.h" +#undef LOG_TAG +#define LOG_TAG "LibSurfaceFlingerUnittests" + +#include "DisplayTransactionTestHelpers.h" + +#include "Fps.h" + +namespace android { +namespace { + +using android::hardware::graphics::composer::V2_4::Error; +using android::hardware::graphics::composer::V2_4::VsyncPeriodChangeTimeline; + +class DisplayModeSwitchingTest : public DisplayTransactionTest { +public: + void SetUp() override { + injectFakeBufferQueueFactory(); + injectFakeNativeWindowSurfaceFactory(); + + PrimaryDisplayVariant::setupHwcHotplugCallExpectations(this); + PrimaryDisplayVariant::setupFramebufferConsumerBufferQueueCallExpectations(this); + PrimaryDisplayVariant::setupFramebufferProducerBufferQueueCallExpectations(this); + PrimaryDisplayVariant::setupNativeWindowSurfaceCreationCallExpectations(this); + PrimaryDisplayVariant::setupHwcGetActiveConfigCallExpectations(this); + + mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED); + + mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this) + .setSupportedModes({kDisplayMode60, kDisplayMode90, kDisplayMode120, + kDisplayMode90DifferentResolution}) + .setActiveMode(kDisplayModeId60) + .inject(); + + setupScheduler(); + + // isVsyncPeriodSwitchSupported should return true, otherwise the SF's HWC proxy + // will call setActiveConfig instead of setActiveConfigWithConstraints. + ON_CALL(*mComposer, isVsyncPeriodSwitchSupported()).WillByDefault(Return(true)); + } + +protected: + void setupScheduler(); + void testChangeRefreshRate(bool isDisplayActive, bool isRefreshRequired); + + sp mDisplay; + mock::EventThread* mAppEventThread; + + const DisplayModeId kDisplayModeId60 = DisplayModeId(0); + const DisplayModePtr kDisplayMode60 = + DisplayMode::Builder(hal::HWConfigId(kDisplayModeId60.value())) + .setId(kDisplayModeId60) + .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get()) + .setVsyncPeriod((60_Hz).getPeriodNsecs()) + .setGroup(0) + .setHeight(1000) + .setWidth(1000) + .build(); + + const DisplayModeId kDisplayModeId90 = DisplayModeId(1); + const DisplayModePtr kDisplayMode90 = + DisplayMode::Builder(hal::HWConfigId(kDisplayModeId90.value())) + .setId(kDisplayModeId90) + .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get()) + .setVsyncPeriod((90_Hz).getPeriodNsecs()) + .setGroup(1) + .setHeight(1000) + .setWidth(1000) + .build(); + + const DisplayModeId kDisplayModeId120 = DisplayModeId(2); + const DisplayModePtr kDisplayMode120 = + DisplayMode::Builder(hal::HWConfigId(kDisplayModeId120.value())) + .setId(kDisplayModeId120) + .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get()) + .setVsyncPeriod((120_Hz).getPeriodNsecs()) + .setGroup(2) + .setHeight(1000) + .setWidth(1000) + .build(); + + const DisplayModeId kDisplayModeId90DifferentResolution = DisplayModeId(3); + const DisplayModePtr kDisplayMode90DifferentResolution = + DisplayMode::Builder(hal::HWConfigId(kDisplayModeId90DifferentResolution.value())) + .setId(kDisplayModeId90DifferentResolution) + .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get()) + .setVsyncPeriod((90_Hz).getPeriodNsecs()) + .setGroup(3) + .setHeight(2000) + .setWidth(2000) + .build(); +}; + +void DisplayModeSwitchingTest::setupScheduler() { + auto eventThread = std::make_unique(); + mAppEventThread = eventThread.get(); + auto sfEventThread = std::make_unique(); + + EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*eventThread, createEventConnection(_, _)) + .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0, + ResyncCallback()))); + + EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) + .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0, + ResyncCallback()))); + + auto vsyncController = std::make_unique(); + auto vsyncTracker = std::make_unique(); + + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + EXPECT_CALL(*vsyncTracker, currentPeriod()) + .WillRepeatedly( + Return(TestableSurfaceFlinger::FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), + std::move(eventThread), std::move(sfEventThread), /*callback*/ nullptr, + /*hasMultipleModes*/ true); +} + +TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithRefreshRequired) { + ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60); + + mFlinger.onActiveDisplayChanged(mDisplay); + + mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), + kDisplayModeId90.value(), false, 0.f, 120.f, 0.f, 120.f); + + ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); + ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kDisplayModeId90); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60); + + // Verify that next commit will call setActiveConfigWithConstraints in HWC + const VsyncPeriodChangeTimeline timeline{.refreshRequired = true}; + EXPECT_CALL(*mComposer, + setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID, + hal::HWConfigId(kDisplayModeId90.value()), _, _)) + .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE))); + + mFlinger.commit(); + + Mock::VerifyAndClearExpectations(mComposer); + ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60); + + // Verify that the next commit will complete the mode change and send + // a onModeChanged event to the framework. + + EXPECT_CALL(*mAppEventThread, onModeChanged(kDisplayMode90)); + mFlinger.commit(); + Mock::VerifyAndClearExpectations(mAppEventThread); + + ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId90); +} + +TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithoutRefreshRequired) { + ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); + + mFlinger.onActiveDisplayChanged(mDisplay); + + mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), + kDisplayModeId90.value(), true, 0.f, 120.f, 0.f, 120.f); + + ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); + ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kDisplayModeId90); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60); + + // Verify that next commit will call setActiveConfigWithConstraints in HWC + // and complete the mode change. + const VsyncPeriodChangeTimeline timeline{.refreshRequired = false}; + EXPECT_CALL(*mComposer, + setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID, + hal::HWConfigId(kDisplayModeId90.value()), _, _)) + .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE))); + + EXPECT_CALL(*mAppEventThread, onModeChanged(kDisplayMode90)); + + mFlinger.commit(); + + ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId90); +} + +TEST_F(DisplayModeSwitchingTest, twoConsecutiveSetDesiredDisplayModeSpecs) { + // Test that if we call setDesiredDisplayModeSpecs while a previous mode change + // is still being processed the later call will be respected. + + ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60); + + mFlinger.onActiveDisplayChanged(mDisplay); + + mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), + kDisplayModeId90.value(), false, 0.f, 120.f, 0.f, 120.f); + + const VsyncPeriodChangeTimeline timeline{.refreshRequired = true}; + EXPECT_CALL(*mComposer, + setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID, + hal::HWConfigId(kDisplayModeId90.value()), _, _)) + .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE))); + + mFlinger.commit(); + + mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), + kDisplayModeId120.value(), false, 0.f, 180.f, 0.f, 180.f); + + ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); + ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kDisplayModeId120); + + EXPECT_CALL(*mComposer, + setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID, + hal::HWConfigId(kDisplayModeId120.value()), _, _)) + .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE))); + + mFlinger.commit(); + + ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); + ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kDisplayModeId120); + + mFlinger.commit(); + + ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId120); +} + +TEST_F(DisplayModeSwitchingTest, changeResolution_OnActiveDisplay_WithoutRefreshRequired) { + ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60); + + mFlinger.onActiveDisplayChanged(mDisplay); + + mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), + kDisplayModeId90DifferentResolution.value(), false, 0.f, + 120.f, 0.f, 120.f); + + ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); + ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kDisplayModeId90DifferentResolution); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60); + + // Verify that next commit will call setActiveConfigWithConstraints in HWC + // and complete the mode change. + const VsyncPeriodChangeTimeline timeline{.refreshRequired = false}; + EXPECT_CALL(*mComposer, + setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID, + hal::HWConfigId( + kDisplayModeId90DifferentResolution.value()), + _, _)) + .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE))); + + EXPECT_CALL(*mAppEventThread, onHotplugReceived(mDisplay->getPhysicalId(), true)); + + // Misc expecations. We don't need to enforce these method calls, but since the helper methods + // already set expectations we should add new ones here, otherwise the test will fail. + EXPECT_CALL(*mConsumer, setDefaultBufferSize(2000, 2000)).WillOnce(Return(NO_ERROR)); + EXPECT_CALL(*mConsumer, consumerConnect(_, false)).WillOnce(Return(NO_ERROR)); + EXPECT_CALL(*mComposer, setClientTargetSlotCount(_)).WillOnce(Return(hal::Error::NONE)); + + // Create a new native surface to be used by the recreated display. + mNativeWindowSurface = nullptr; + injectFakeNativeWindowSurfaceFactory(); + PrimaryDisplayVariant::setupNativeWindowSurfaceCreationCallExpectations(this); + + const auto displayToken = mDisplay->getDisplayToken().promote(); + + mFlinger.commit(); + + // The DisplayDevice will be destroyed and recreated, + // so we need to update with the new instance. + mDisplay = mFlinger.getDisplay(displayToken); + + ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId90DifferentResolution); +} + +} // namespace +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 4c5789e47f..6ce72a809e 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "BufferQueueLayer.h" #include "BufferStateLayer.h" @@ -305,6 +306,11 @@ public: return mFlinger->destroyDisplay(displayToken); } + auto getDisplay(const sp& displayToken) { + Mutex::Autolock lock(mFlinger->mStateLock); + return mFlinger->getDisplayDeviceLocked(displayToken); + } + void enableHalVirtualDisplays(bool enable) { mFlinger->enableHalVirtualDisplays(enable); } auto setupNewDisplayDeviceInternal( @@ -393,6 +399,21 @@ public: return SurfaceFlinger::calculateMaxAcquiredBufferCount(refreshRate, presentLatency); } + auto setDesiredDisplayModeSpecs(const sp& displayToken, ui::DisplayModeId defaultMode, + bool allowGroupSwitching, float primaryRefreshRateMin, + float primaryRefreshRateMax, float appRequestRefreshRateMin, + float appRequestRefreshRateMax) { + return mFlinger->setDesiredDisplayModeSpecs(displayToken, defaultMode, allowGroupSwitching, + primaryRefreshRateMin, primaryRefreshRateMax, + appRequestRefreshRateMin, + appRequestRefreshRateMax); + } + + void onActiveDisplayChanged(const sp& activeDisplay) { + Mutex::Autolock lock(mFlinger->mStateLock); + mFlinger->onActiveDisplayChangedLocked(activeDisplay); + } + /* ------------------------------------------------------------------------ * Read-only access to private data to assert post-conditions. */ @@ -480,7 +501,7 @@ public: static constexpr hal::HWDisplayId DEFAULT_HWC_DISPLAY_ID = 1000; static constexpr int32_t DEFAULT_WIDTH = 1920; static constexpr int32_t DEFAULT_HEIGHT = 1280; - static constexpr int32_t DEFAULT_VSYNC_PERIOD = 16'666'666; + static constexpr int32_t DEFAULT_VSYNC_PERIOD = 16'666'667; static constexpr int32_t DEFAULT_CONFIG_GROUP = 7; static constexpr int32_t DEFAULT_DPI = 320; static constexpr hal::HWConfigId DEFAULT_ACTIVE_CONFIG = 0; @@ -634,10 +655,10 @@ public: mCreationArgs.connectionType = connectionType; mCreationArgs.isPrimary = isPrimary; - mActiveModeId = DisplayModeId(0); + mCreationArgs.activeModeId = DisplayModeId(0); DisplayModePtr activeMode = DisplayMode::Builder(FakeHwcDisplayInjector::DEFAULT_ACTIVE_CONFIG) - .setId(mActiveModeId) + .setId(mCreationArgs.activeModeId) .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0)) .setWidth(FakeHwcDisplayInjector::DEFAULT_WIDTH) .setHeight(FakeHwcDisplayInjector::DEFAULT_HEIGHT) @@ -673,7 +694,7 @@ public: auto& mutableDisplayDevice() { return mFlinger.mutableDisplays()[mDisplayToken]; } auto& setActiveMode(DisplayModeId mode) { - mActiveModeId = mode; + mCreationArgs.activeModeId = mode; return *this; } @@ -728,14 +749,29 @@ public: const auto physicalId = PhysicalDisplayId::tryCast(*displayId); LOG_ALWAYS_FATAL_IF(!physicalId); LOG_ALWAYS_FATAL_IF(!mHwcDisplayId); - state.physical = {.id = *physicalId, .type = *type, .hwcDisplayId = *mHwcDisplayId}; + + const DisplayModePtr activeModePtr = + *std::find_if(mCreationArgs.supportedModes.begin(), + mCreationArgs.supportedModes.end(), [&](DisplayModePtr mode) { + return mode->getId() == mCreationArgs.activeModeId; + }); + state.physical = {.id = *physicalId, + .type = *type, + .hwcDisplayId = *mHwcDisplayId, + .deviceProductInfo = {}, + .supportedModes = mCreationArgs.supportedModes, + .activeMode = activeModePtr}; } state.isSecure = mCreationArgs.isSecure; + mCreationArgs.refreshRateConfigs = + std::make_shared(mCreationArgs.supportedModes, + mCreationArgs.activeModeId); + sp device = new DisplayDevice(mCreationArgs); if (!device->isVirtual()) { - device->setActiveMode(mActiveModeId); + device->setActiveMode(mCreationArgs.activeModeId); } mFlinger.mutableDisplays().emplace(mDisplayToken, device); mFlinger.mutableCurrentState().displays.add(mDisplayToken, state); @@ -753,7 +789,6 @@ public: sp mDisplayToken = new BBinder(); DisplayDeviceCreationArgs mCreationArgs; const std::optional mHwcDisplayId; - DisplayModeId mActiveModeId; }; private: -- cgit v1.2.3-59-g8ed1b From f155b3ed59455b0fd301a4e8412164576e540995 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 18 Nov 2021 07:29:25 -0800 Subject: Input injection: Assume transformed values are in logical display space Previously, we assumed that, for injected MotionEvents, the values in the PointerCoords were in logical display space. This is not always true, as the PointerCoords for events generated by dispatcher are in the display space, and are only in the logical display space once their transform is applied. In this CL we assume that the transformed PointerCoords values are in the logical display space before converting it to the display space. Additionally, we set the offset values to 0, because they are now already included in the transform. Bug: 206842332 Test: atest inputflinger_tests Test: manual with accessibility over (e.g. Magnification) in different orientations Change-Id: I65c284e5e00ed7c1b60b31269e16ba6f045071c2 --- .../inputflinger/dispatcher/InputDispatcher.cpp | 55 ++++++++-------------- services/inputflinger/dispatcher/InputDispatcher.h | 4 +- .../inputflinger/tests/InputDispatcher_test.cpp | 27 +++++++++++ 3 files changed, 50 insertions(+), 36 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 7f68d1b8b1..3fd1c8aa27 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -506,12 +506,6 @@ bool isConnectionResponsive(const Connection& connection) { return true; } -vec2 transformWithoutTranslation(const ui::Transform& transform, float x, float y) { - const vec2 transformedXy = transform.transform(x, y); - const vec2 transformedOrigin = transform.transform(0, 0); - return transformedXy - transformedOrigin; -} - // Returns true if the event type passed as argument represents a user activity. bool isUserActivityEvent(const EventEntry& eventEntry) { switch (eventEntry.type) { @@ -4214,10 +4208,8 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawXCursorPosition(), motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), - pointerProperties, samplePointerCoords, - motionEvent.getXOffset(), - motionEvent.getYOffset()); - transformMotionEntryForInjectionLocked(*injectedEntry); + pointerProperties, samplePointerCoords, 0, 0); + transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(injectedEntry)); for (size_t i = motionEvent.getHistorySize(); i > 0; i--) { sampleEventTimes += 1; @@ -4236,9 +4228,9 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), pointerProperties, - samplePointerCoords, motionEvent.getXOffset(), - motionEvent.getYOffset()); - transformMotionEntryForInjectionLocked(*nextInjectedEntry); + samplePointerCoords, 0, 0); + transformMotionEntryForInjectionLocked(*nextInjectedEntry, + motionEvent.getTransform()); injectedEntries.push(std::move(nextInjectedEntry)); } break; @@ -4402,35 +4394,28 @@ void InputDispatcher::setInjectionResult(EventEntry& entry, } } -void InputDispatcher::transformMotionEntryForInjectionLocked(MotionEntry& entry) const { - const bool isRelativeMouseEvent = isFromSource(entry.source, AINPUT_SOURCE_MOUSE_RELATIVE); - if (!isRelativeMouseEvent && !isFromSource(entry.source, AINPUT_SOURCE_CLASS_POINTER)) { - return; - } - +void InputDispatcher::transformMotionEntryForInjectionLocked( + MotionEntry& entry, const ui::Transform& injectedTransform) const { // Input injection works in the logical display coordinate space, but the input pipeline works // display space, so we need to transform the injected events accordingly. const auto it = mDisplayInfos.find(entry.displayId); if (it == mDisplayInfos.end()) return; - const auto& transformToDisplay = it->second.transform.inverse(); + const auto& transformToDisplay = it->second.transform.inverse() * injectedTransform; for (uint32_t i = 0; i < entry.pointerCount; i++) { PointerCoords& pc = entry.pointerCoords[i]; - const auto xy = isRelativeMouseEvent - ? transformWithoutTranslation(transformToDisplay, pc.getX(), pc.getY()) - : transformToDisplay.transform(pc.getXYValue()); - pc.setAxisValue(AMOTION_EVENT_AXIS_X, xy.x); - pc.setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y); - - // Axes with relative values never represent points on a screen, so they should never have - // translation applied. If a device does not report relative values, these values are always - // 0, and will remain unaffected by the following operation. - const auto rel = - transformWithoutTranslation(transformToDisplay, - pc.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), - pc.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)); - pc.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, rel.x); - pc.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, rel.y); + // Make a copy of the injected coords. We cannot change them in place because some of them + // are interdependent (for example, X coordinate might depend on the Y coordinate). + PointerCoords injectedCoords = entry.pointerCoords[i]; + + BitSet64 bits(injectedCoords.bits); + while (!bits.isEmpty()) { + const auto axis = static_cast(bits.clearFirstMarkedBit()); + const float value = + MotionEvent::calculateTransformedAxisValue(axis, entry.source, + transformToDisplay, injectedCoords); + pc.setAxisValue(axis, value); + } } } diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 8a551cfca1..6f05670943 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -280,7 +280,9 @@ private: bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); void setInjectionResult(EventEntry& entry, android::os::InputEventInjectionResult injectionResult); - void transformMotionEntryForInjectionLocked(MotionEntry&) const REQUIRES(mLock); + void transformMotionEntryForInjectionLocked(MotionEntry&, + const ui::Transform& injectedTransform) const + REQUIRES(mLock); std::condition_variable mInjectionSyncFinished; void incrementPendingForegroundDispatches(EventEntry& entry); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 515a01e137..eaea4e26c4 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -2079,6 +2079,33 @@ TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) { secondWindow->assertNoEvents(); } +// Ensure that when a MotionEvent that has a custom transform is injected, the post-transformed +// event should be treated as being in the logical display space. +TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisplaySpace) { + auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); + + const std::array matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0}; + ui::Transform injectedEventTransform; + injectedEventTransform.set(matrix); + const vec2 expectedPoint{75, 55}; // The injected point in the logical display space. + const vec2 untransformedPoint = injectedEventTransform.inverse().transform(expectedPoint); + + MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(untransformedPoint.x) + .y(untransformedPoint.y)) + .build(); + event.transform(matrix); + + injectMotionEvent(mDispatcher, event, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT); + + firstWindow->consumeMotionDown(); + secondWindow->assertNoEvents(); +} + TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) { auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); -- cgit v1.2.3-59-g8ed1b From 5e6b390919a9786a50f9d5cbd539e9dc53ad78c2 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 18 Nov 2021 07:54:09 -0800 Subject: Remove x/y offset from MotionEntry Window or display offsets are now captured in the various transforms, so we can remove the ability to specify the offset by itself. Bug: 188939842 Test: presubmit Test: atest inputflinger_tests Change-Id: Ifd359ebb03850bb30efb358e84f0a7e77260a8b2 --- include/input/Input.h | 5 ++--- libs/input/Input.cpp | 5 ----- services/inputflinger/dispatcher/Entry.cpp | 5 +---- services/inputflinger/dispatcher/Entry.h | 3 +-- services/inputflinger/dispatcher/InputDispatcher.cpp | 10 +++++----- services/inputflinger/dispatcher/InputState.cpp | 6 ++---- 6 files changed, 11 insertions(+), 23 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index 1e06257591..1c79c4a21c 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -377,7 +377,6 @@ struct PointerCoords { // window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR // axes, however the window scaling will not. void scale(float globalScale, float windowXScale, float windowYScale); - void applyOffset(float xOffset, float yOffset); void transform(const ui::Transform& transform); @@ -567,7 +566,7 @@ public: inline float getYOffset() const { return mTransform.ty(); } - inline ui::Transform getTransform() const { return mTransform; } + inline const ui::Transform& getTransform() const { return mTransform; } inline float getXPrecision() const { return mXPrecision; } @@ -583,7 +582,7 @@ public: void setCursorPosition(float x, float y); - ui::Transform getRawTransform() const { return mRawTransform; } + inline const ui::Transform& getRawTransform() const { return mRawTransform; } static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); } diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 8974b22c86..69ea7dfcb5 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -343,11 +343,6 @@ void PointerCoords::scale(float globalScaleFactor, float windowXScale, float win scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_Y, windowYScale); } -void PointerCoords::applyOffset(float xOffset, float yOffset) { - setAxisValue(AMOTION_EVENT_AXIS_X, getX() + xOffset); - setAxisValue(AMOTION_EVENT_AXIS_Y, getY() + yOffset); -} - #ifdef __linux__ status_t PointerCoords::readFromParcel(Parcel* parcel) { bits = parcel->readInt64(); diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index 1674afd02e..3d0818b738 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -214,7 +214,7 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords, float xOffset, float yOffset) + const PointerCoords* pointerCoords) : EventEntry(id, Type::MOTION, eventTime, policyFlags), deviceId(deviceId), source(source), @@ -235,9 +235,6 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); this->pointerCoords[i].copyFrom(pointerCoords[i]); - if (xOffset || yOffset) { - this->pointerCoords[i].applyOffset(xOffset, yOffset); - } } } diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index 477781a2ad..0f792967eb 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -184,8 +184,7 @@ struct MotionEntry : EventEntry { int32_t metaState, int32_t buttonState, MotionClassification classification, int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xOffset, float yOffset); + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); std::string getDescription() const override; ~MotionEntry() override; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 3fd1c8aa27..04ff599f13 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -378,7 +378,7 @@ std::unique_ptr createDispatchEntry(const InputTarget& inputTarge motionEntry.yPrecision, motionEntry.xCursorPosition, motionEntry.yCursorPosition, motionEntry.downTime, motionEntry.pointerCount, motionEntry.pointerProperties, - pointerCoords.data(), 0 /* xOffset */, 0 /* yOffset */); + pointerCoords.data()); if (motionEntry.injectionState) { combinedMotionEntry->injectionState = motionEntry.injectionState; @@ -3752,7 +3752,7 @@ std::unique_ptr InputDispatcher::splitMotionEvent( originalMotionEntry.xCursorPosition, originalMotionEntry.yCursorPosition, originalMotionEntry.downTime, splitPointerCount, - splitPointerProperties, splitPointerCoords, 0, 0); + splitPointerProperties, splitPointerCoords); if (originalMotionEntry.injectionState) { splitMotionEntry->injectionState = originalMotionEntry.injectionState; @@ -3978,7 +3978,7 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { args->xPrecision, args->yPrecision, args->xCursorPosition, args->yCursorPosition, args->downTime, args->pointerCount, - args->pointerProperties, args->pointerCoords, 0, 0); + args->pointerProperties, args->pointerCoords); if (args->id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID && IdGenerator::getSource(args->id) == IdGenerator::Source::INPUT_READER && @@ -4208,7 +4208,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawXCursorPosition(), motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), - pointerProperties, samplePointerCoords, 0, 0); + pointerProperties, samplePointerCoords); transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(injectedEntry)); for (size_t i = motionEvent.getHistorySize(); i > 0; i--) { @@ -4228,7 +4228,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), pointerProperties, - samplePointerCoords, 0, 0); + samplePointerCoords); transformMotionEntryForInjectionLocked(*nextInjectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(nextInjectedEntry)); diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index 3bb0bc995c..ad3c6159ef 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -296,8 +296,7 @@ std::vector> InputState::synthesizeCancelationEvents memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, memento.pointerCount, memento.pointerProperties, - memento.pointerCoords, 0 /*xOffset*/, - 0 /*yOffset*/)); + memento.pointerCoords)); } } return events; @@ -349,8 +348,7 @@ std::vector> InputState::synthesizePointerDownEvents AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, - pointerCount, pointerProperties, pointerCoords, - 0 /*xOffset*/, 0 /*yOffset*/)); + pointerCount, pointerProperties, pointerCoords)); } memento.firstNewPointerIdx = INVALID_POINTER_INDEX; -- cgit v1.2.3-59-g8ed1b From 068173d9076ca25fa5cc008a116e4ec22503b9be Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Wed, 11 Aug 2021 17:22:59 -0700 Subject: SF: Add VsyncSchedule skeleton Pull the Scheduler::VsyncSchedule struct and related code into its own file, as it will be extended with more per-display state, e.g. reactor registrations, resync state machine, etc. Add for feature flags. Move Scheduler into its namespace. Bug: 185535769 Test: libsurfaceflinger_unittest Change-Id: I6e10893632c5abf40380df924791d1fcc27c3cc2 --- services/surfaceflinger/Android.bp | 3 +- services/surfaceflinger/BufferQueueLayer.cpp | 5 +- services/surfaceflinger/BufferStateLayer.cpp | 5 +- services/surfaceflinger/DisplayDevice.cpp | 4 +- services/surfaceflinger/DisplayDevice.h | 2 +- services/surfaceflinger/Layer.cpp | 4 +- services/surfaceflinger/Scheduler/LayerHistory.h | 6 +- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 8 +- services/surfaceflinger/Scheduler/Scheduler.cpp | 216 +++++++-------------- services/surfaceflinger/Scheduler/Scheduler.h | 100 ++++------ services/surfaceflinger/Scheduler/VSyncReactor.cpp | 4 +- services/surfaceflinger/Scheduler/VSyncReactor.h | 2 +- .../surfaceflinger/Scheduler/VsyncController.h | 10 +- .../surfaceflinger/Scheduler/VsyncSchedule.cpp | 113 +++++++++++ services/surfaceflinger/Scheduler/VsyncSchedule.h | 75 +++++++ .../Scheduler/include/scheduler/Features.h | 34 ++++ services/surfaceflinger/SurfaceFlinger.cpp | 43 ++-- services/surfaceflinger/SurfaceFlinger.h | 7 +- services/surfaceflinger/SurfaceFlingerFactory.h | 4 - .../tests/unittests/CompositionTest.cpp | 2 +- .../unittests/DisplayDevice_InitiateModeChange.cpp | 2 +- .../unittests/DisplayTransactionTestHelpers.h | 2 +- .../tests/unittests/FpsReporterTest.cpp | 4 + .../tests/unittests/LayerHistoryTest.cpp | 13 +- .../tests/unittests/SchedulerTest.cpp | 43 ++-- .../tests/unittests/SetFrameRateTest.cpp | 2 + .../SurfaceFlinger_NotifyPowerBoostTest.cpp | 7 +- .../tests/unittests/TestableScheduler.h | 39 ++-- .../tests/unittests/TestableSurfaceFlinger.h | 20 +- .../tests/unittests/TransactionApplicationTest.cpp | 5 +- .../tests/unittests/mock/MockSchedulerCallback.h | 17 +- .../tests/unittests/mock/MockVsyncController.h | 2 +- 32 files changed, 461 insertions(+), 342 deletions(-) create mode 100644 services/surfaceflinger/Scheduler/VsyncSchedule.cpp create mode 100644 services/surfaceflinger/Scheduler/VsyncSchedule.h create mode 100644 services/surfaceflinger/Scheduler/include/scheduler/Features.h diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 29636f84f5..c9fb7bc876 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -194,9 +194,10 @@ filegroup { "Scheduler/Timer.cpp", "Scheduler/VSyncDispatchTimerQueue.cpp", "Scheduler/VSyncPredictor.cpp", - "Scheduler/VsyncModulator.cpp", "Scheduler/VSyncReactor.cpp", "Scheduler/VsyncConfiguration.cpp", + "Scheduler/VsyncModulator.cpp", + "Scheduler/VsyncSchedule.cpp", "StartPropertySetThread.cpp", "SurfaceFlinger.cpp", "SurfaceFlingerDefaultFactory.cpp", diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index dec7cc0806..926aa1dfb2 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -372,8 +372,9 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { // Add this buffer from our internal queue tracker { // Autolock scope const nsecs_t presentTime = item.mIsAutoTimestamp ? 0 : item.mTimestamp; - mFlinger->mScheduler->recordLayerHistory(this, presentTime, - LayerHistory::LayerUpdateType::Buffer); + + using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; + mFlinger->mScheduler->recordLayerHistory(this, presentTime, LayerUpdateType::Buffer); Mutex::Autolock lock(mQueueItemLock); // Reset the frame number tracker when we receive the first buffer after diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index b4ccb803e9..7d40fc87f9 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -476,8 +476,9 @@ bool BufferStateLayer::setBuffer(const BufferData& bufferData, nsecs_t postTime, return static_cast(0); }(); - mFlinger->mScheduler->recordLayerHistory(this, presentTime, - LayerHistory::LayerUpdateType::Buffer); + + using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; + mFlinger->mScheduler->recordLayerHistory(this, presentTime, LayerUpdateType::Buffer); addFrameEvent(mDrawingState.acquireFence, postTime, isAutoTimestamp ? 0 : desiredPresentTime); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index fd09ae4066..76bbe2c58f 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -483,7 +483,7 @@ bool DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info) { std::scoped_lock lock(mActiveModeLock); if (mDesiredActiveModeChanged) { // If a mode change is pending, just cache the latest request in mDesiredActiveMode - const Scheduler::ModeEvent prevConfig = mDesiredActiveMode.event; + const auto prevConfig = mDesiredActiveMode.event; mDesiredActiveMode = info; mDesiredActiveMode.event = mDesiredActiveMode.event | prevConfig; return false; @@ -508,7 +508,7 @@ std::optional DisplayDevice::getDesiredActiveMode void DisplayDevice::clearDesiredActiveModeState() { std::scoped_lock lock(mActiveModeLock); - mDesiredActiveMode.event = Scheduler::ModeEvent::None; + mDesiredActiveMode.event = scheduler::DisplayModeEvent::None; mDesiredActiveModeChanged = false; } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 4b9718f608..324145ef47 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -190,7 +190,7 @@ public: struct ActiveModeInfo { DisplayModePtr mode; - scheduler::RefreshRateConfigEvent event = scheduler::RefreshRateConfigEvent::None; + scheduler::DisplayModeEvent event = scheduler::DisplayModeEvent::None; bool operator!=(const ActiveModeInfo& other) const { return mode != other.mode || event != other.event; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 968a49d526..b3ea94fd94 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1293,8 +1293,8 @@ bool Layer::setFrameRateForLayerTree(FrameRate frameRate) { mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); - mFlinger->mScheduler->recordLayerHistory(this, systemTime(), - LayerHistory::LayerUpdateType::SetFrameRate); + using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; + mFlinger->mScheduler->recordLayerHistory(this, systemTime(), LayerUpdateType::SetFrameRate); return true; } diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index 92236f560a..8d56951363 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -31,11 +31,9 @@ namespace android { class Layer; -class TestableScheduler; namespace scheduler { -class LayerHistoryTest; class LayerInfo; class LayerHistory { @@ -75,8 +73,8 @@ public: std::string dump() const; private: - friend LayerHistoryTest; - friend TestableScheduler; + friend class LayerHistoryTest; + friend class TestableScheduler; using LayerPair = std::pair>; using LayerInfos = std::vector; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 8a1c2062a6..492feb14df 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -37,11 +37,11 @@ namespace android::scheduler { using namespace std::chrono_literals; -enum class RefreshRateConfigEvent : unsigned { None = 0b0, Changed = 0b1 }; +enum class DisplayModeEvent : unsigned { None = 0b0, Changed = 0b1 }; -inline RefreshRateConfigEvent operator|(RefreshRateConfigEvent lhs, RefreshRateConfigEvent rhs) { - using T = std::underlying_type_t; - return static_cast(static_cast(lhs) | static_cast(rhs)); +inline DisplayModeEvent operator|(DisplayModeEvent lhs, DisplayModeEvent rhs) { + using T = std::underlying_type_t; + return static_cast(static_cast(lhs) | static_cast(rhs)); } using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 4d72798086..cbe4552b0b 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -46,11 +46,8 @@ #include "OneShotTimer.h" #include "SchedulerUtils.h" #include "SurfaceFlingerProperties.h" -#include "Timer.h" -#include "VSyncDispatchTimerQueue.h" #include "VSyncPredictor.h" #include "VSyncReactor.h" -#include "VsyncController.h" #define RETURN_IF_INVALID_HANDLE(handle, ...) \ do { \ @@ -60,68 +57,14 @@ } \ } while (false) -using namespace std::string_literals; +namespace android::scheduler { -namespace android { - -using gui::WindowInfo; - -namespace { - -std::unique_ptr createVSyncTracker() { - // TODO(b/144707443): Tune constants. - constexpr int kDefaultRate = 60; - constexpr auto initialPeriod = std::chrono::duration>(1); - constexpr nsecs_t idealPeriod = - std::chrono::duration_cast(initialPeriod).count(); - constexpr size_t vsyncTimestampHistorySize = 20; - constexpr size_t minimumSamplesForPrediction = 6; - constexpr uint32_t discardOutlierPercent = 20; - return std::make_unique(idealPeriod, vsyncTimestampHistorySize, - minimumSamplesForPrediction, - discardOutlierPercent); -} - -std::unique_ptr createVSyncDispatch(scheduler::VSyncTracker& tracker) { - // TODO(b/144707443): Tune constants. - constexpr std::chrono::nanoseconds vsyncMoveThreshold = 3ms; - constexpr std::chrono::nanoseconds timerSlack = 500us; - return std::make_unique< - scheduler::VSyncDispatchTimerQueue>(std::make_unique(), tracker, - timerSlack.count(), vsyncMoveThreshold.count()); -} - -const char* toContentDetectionString(bool useContentDetection) { - return useContentDetection ? "on" : "off"; -} - -} // namespace - -class PredictedVsyncTracer { -public: - PredictedVsyncTracer(scheduler::VSyncDispatch& dispatch) - : mRegistration(dispatch, std::bind(&PredictedVsyncTracer::callback, this), - "PredictedVsyncTracer") { - scheduleRegistration(); - } - -private: - TracedOrdinal mParity = {"VSYNC-predicted", 0}; - scheduler::VSyncCallbackRegistration mRegistration; - - void scheduleRegistration() { mRegistration.schedule({0, 0, 0}); } - - void callback() { - mParity = !mParity; - scheduleRegistration(); - } -}; - -Scheduler::Scheduler(ICompositor& compositor, ISchedulerCallback& callback, Options options) - : impl::MessageQueue(compositor), mOptions(options), mSchedulerCallback(callback) {} +Scheduler::Scheduler(ICompositor& compositor, ISchedulerCallback& callback, FeatureFlags features) + : impl::MessageQueue(compositor), mFeatures(features), mSchedulerCallback(callback) {} void Scheduler::startTimers() { using namespace sysprop; + using namespace std::string_literals; if (const int64_t millis = set_touch_timer_ms(0); millis > 0) { // Touch events are coming to SF every 100ms, so the timer needs to be higher than that @@ -154,27 +97,14 @@ void Scheduler::run() { } } -void Scheduler::createVsyncSchedule(bool supportKernelTimer) { - auto clock = std::make_unique(); - auto tracker = createVSyncTracker(); - auto dispatch = createVSyncDispatch(*tracker); - - // TODO(b/144707443): Tune constants. - constexpr size_t pendingFenceLimit = 20; - auto controller = - std::make_unique(std::move(clock), *tracker, pendingFenceLimit, - supportKernelTimer); - mVsyncSchedule = {std::move(controller), std::move(tracker), std::move(dispatch)}; - - if (base::GetBoolProperty("debug.sf.show_predicted_vsync", false)) { - mPredictedVsyncTracer = std::make_unique(*mVsyncSchedule.dispatch); - } +void Scheduler::createVsyncSchedule(FeatureFlags features) { + mVsyncSchedule.emplace(features); } std::unique_ptr Scheduler::makePrimaryDispSyncSource( const char* name, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, bool traceVsync) { - return std::make_unique(*mVsyncSchedule.dispatch, workDuration, + return std::make_unique(getVsyncDispatch(), workDuration, readyDuration, traceVsync, name); } @@ -210,7 +140,7 @@ bool Scheduler::isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const { return true; } - return mVsyncSchedule.tracker->isVSyncInPhase(expectedVsyncTimestamp, *frameRate); + return mVsyncSchedule->getTracker().isVSyncInPhase(expectedVsyncTimestamp, *frameRate); } impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() const { @@ -245,7 +175,7 @@ impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction( }; } -Scheduler::ConnectionHandle Scheduler::createConnection( +ConnectionHandle Scheduler::createConnection( const char* connectionName, frametimeline::TokenManager* tokenManager, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, impl::EventThread::InterceptVSyncsCallback interceptCallback) { @@ -259,7 +189,7 @@ Scheduler::ConnectionHandle Scheduler::createConnection( return createConnection(std::move(eventThread)); } -Scheduler::ConnectionHandle Scheduler::createConnection(std::unique_ptr eventThread) { +ConnectionHandle Scheduler::createConnection(std::unique_ptr eventThread) { const ConnectionHandle handle = ConnectionHandle{mNextConnectionHandleId++}; ALOGV("Creating a connection handle with ID %" PRIuPTR, handle.id); @@ -346,24 +276,24 @@ void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDis void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) { { - std::lock_guard lock(mFeatureStateLock); + std::lock_guard lock(mPolicyLock); // Cache the last reported modes for primary display. - mFeatures.cachedModeChangedParams = {handle, mode}; + mPolicy.cachedModeChangedParams = {handle, mode}; // Invalidate content based refresh rate selection so it could be calculated // again for the new refresh rate. - mFeatures.contentRequirements.clear(); + mPolicy.contentRequirements.clear(); } onNonPrimaryDisplayModeChanged(handle, mode); } void Scheduler::dispatchCachedReportedMode() { // Check optional fields first. - if (!mFeatures.mode) { + if (!mPolicy.mode) { ALOGW("No mode ID found, not dispatching cached mode."); return; } - if (!mFeatures.cachedModeChangedParams.has_value()) { + if (!mPolicy.cachedModeChangedParams) { ALOGW("No mode changed params found, not dispatching cached mode."); return; } @@ -372,18 +302,18 @@ void Scheduler::dispatchCachedReportedMode() { // mode change is in progress. In that case we shouldn't dispatch an event // as it will be dispatched when the current mode changes. if (std::scoped_lock lock(mRefreshRateConfigsLock); - mRefreshRateConfigs->getCurrentRefreshRate().getMode() != mFeatures.mode) { + mRefreshRateConfigs->getCurrentRefreshRate().getMode() != mPolicy.mode) { return; } // If there is no change from cached mode, there is no need to dispatch an event - if (mFeatures.mode == mFeatures.cachedModeChangedParams->mode) { + if (mPolicy.mode == mPolicy.cachedModeChangedParams->mode) { return; } - mFeatures.cachedModeChangedParams->mode = mFeatures.mode; - onNonPrimaryDisplayModeChanged(mFeatures.cachedModeChangedParams->handle, - mFeatures.cachedModeChangedParams->mode); + mPolicy.cachedModeChangedParams->mode = mPolicy.mode; + onNonPrimaryDisplayModeChanged(mPolicy.cachedModeChangedParams->handle, + mPolicy.cachedModeChangedParams->mode); } void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) { @@ -424,12 +354,12 @@ void Scheduler::setDuration(ConnectionHandle handle, std::chrono::nanoseconds wo } DisplayStatInfo Scheduler::getDisplayStatInfo(nsecs_t now) { - const auto vsyncTime = mVsyncSchedule.tracker->nextAnticipatedVSyncTimeFrom(now); - const auto vsyncPeriod = mVsyncSchedule.tracker->currentPeriod(); + const auto vsyncTime = mVsyncSchedule->getTracker().nextAnticipatedVSyncTimeFrom(now); + const auto vsyncPeriod = mVsyncSchedule->getTracker().currentPeriod(); return DisplayStatInfo{.vsyncTime = vsyncTime, .vsyncPeriod = vsyncPeriod}; } -Scheduler::ConnectionHandle Scheduler::enableVSyncInjection(bool enable) { +ConnectionHandle Scheduler::enableVSyncInjection(bool enable) { if (mInjectVSyncs == enable) { return {}; } @@ -470,7 +400,7 @@ bool Scheduler::injectVSync(nsecs_t when, nsecs_t expectedVSyncTime, nsecs_t dea void Scheduler::enableHardwareVsync() { std::lock_guard lock(mHWVsyncLock); if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) { - mVsyncSchedule.tracker->resetModel(); + mVsyncSchedule->getTracker().resetModel(); mSchedulerCallback.setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } @@ -523,10 +453,10 @@ void Scheduler::resync() { void Scheduler::setVsyncPeriod(nsecs_t period) { std::lock_guard lock(mHWVsyncLock); - mVsyncSchedule.controller->startPeriodTransition(period); + mVsyncSchedule->getController().startPeriodTransition(period); if (!mPrimaryHWVsyncEnabled) { - mVsyncSchedule.tracker->resetModel(); + mVsyncSchedule->getTracker().resetModel(); mSchedulerCallback.setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } @@ -539,8 +469,9 @@ void Scheduler::addResyncSample(nsecs_t timestamp, std::optional hwcVsy { // Scope for the lock std::lock_guard lock(mHWVsyncLock); if (mPrimaryHWVsyncEnabled) { - needsHwVsync = mVsyncSchedule.controller->addHwVsyncTimestamp(timestamp, hwcVsyncPeriod, - periodFlushed); + needsHwVsync = + mVsyncSchedule->getController().addHwVsyncTimestamp(timestamp, hwcVsyncPeriod, + periodFlushed); } } @@ -551,24 +482,23 @@ void Scheduler::addResyncSample(nsecs_t timestamp, std::optional hwcVsy } } -void Scheduler::addPresentFence(const std::shared_ptr& fenceTime) { - if (mVsyncSchedule.controller->addPresentFence(fenceTime)) { +void Scheduler::addPresentFence(std::shared_ptr fence) { + if (mVsyncSchedule->getController().addPresentFence(std::move(fence))) { enableHardwareVsync(); } else { disableHardwareVsync(false); } } -void Scheduler::setIgnorePresentFences(bool ignore) { - mVsyncSchedule.controller->setIgnorePresentFences(ignore); -} - void Scheduler::registerLayer(Layer* layer) { + using WindowType = gui::WindowInfo::Type; + scheduler::LayerHistory::LayerVoteType voteType; - if (!mOptions.useContentDetection || layer->getWindowType() == WindowInfo::Type::STATUS_BAR) { + if (!mFeatures.test(Feature::kContentDetection) || + layer->getWindowType() == WindowType::STATUS_BAR) { voteType = scheduler::LayerHistory::LayerVoteType::NoVote; - } else if (layer->getWindowType() == WindowInfo::Type::WALLPAPER) { + } else if (layer->getWindowType() == WindowType::WALLPAPER) { // Running Wallpaper at Min is considered as part of content detection. voteType = scheduler::LayerHistory::LayerVoteType::Min; } else { @@ -615,13 +545,13 @@ void Scheduler::chooseRefreshRateForContent() { bool frameRateChanged; bool frameRateOverridesChanged; { - std::lock_guard lock(mFeatureStateLock); - mFeatures.contentRequirements = summary; + std::lock_guard lock(mPolicyLock); + mPolicy.contentRequirements = summary; newMode = calculateRefreshRateModeId(&consideredSignals); frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); - if (mFeatures.mode == newMode) { + if (mPolicy.mode == newMode) { // We don't need to change the display mode, but we might need to send an event // about a mode change, since it was suppressed due to a previous idleConsidered if (!consideredSignals.idle) { @@ -629,15 +559,16 @@ void Scheduler::chooseRefreshRateForContent() { } frameRateChanged = false; } else { - mFeatures.mode = newMode; + mPolicy.mode = newMode; frameRateChanged = true; } } if (frameRateChanged) { - auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); + const auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); + mSchedulerCallback.changeRefreshRate(newRefreshRate, - consideredSignals.idle ? ModeEvent::None - : ModeEvent::Changed); + consideredSignals.idle ? DisplayModeEvent::None + : DisplayModeEvent::Changed); } if (frameRateOverridesChanged) { mSchedulerCallback.triggerOnFrameRateOverridesChanged(); @@ -660,8 +591,8 @@ void Scheduler::onTouchHint() { void Scheduler::setDisplayPowerState(bool normal) { { - std::lock_guard lock(mFeatureStateLock); - mFeatures.isDisplayPowerStateNormal = normal; + std::lock_guard lock(mPolicyLock); + mPolicy.isDisplayPowerStateNormal = normal; } if (mDisplayPowerTimer) { @@ -703,7 +634,7 @@ void Scheduler::kernelIdleTimerCallback(TimerState state) { } void Scheduler::idleTimerCallback(TimerState state) { - handleTimerStateChanged(&mFeatures.idleTimer, state); + handleTimerStateChanged(&mPolicy.idleTimer, state); ATRACE_INT("ExpiredIdleTimer", static_cast(state)); } @@ -713,14 +644,14 @@ void Scheduler::touchTimerCallback(TimerState state) { // Clear layer history to get fresh FPS detection. // NOTE: Instead of checking all the layers, we should be checking the layer // that is currently on top. b/142507166 will give us this capability. - if (handleTimerStateChanged(&mFeatures.touch, touch)) { + if (handleTimerStateChanged(&mPolicy.touch, touch)) { mLayerHistory.clear(); } ATRACE_INT("TouchState", static_cast(touch)); } void Scheduler::displayPowerTimerCallback(TimerState state) { - handleTimerStateChanged(&mFeatures.displayPowerTimer, state); + handleTimerStateChanged(&mPolicy.displayPowerTimer, state); ATRACE_INT("ExpiredDisplayPowerTimer", static_cast(state)); } @@ -730,7 +661,7 @@ void Scheduler::dump(std::string& result) const { StringAppendF(&result, "+ Touch timer: %s\n", mTouchTimer ? mTouchTimer->dump().c_str() : "off"); StringAppendF(&result, "+ Content detection: %s %s\n\n", - toContentDetectionString(mOptions.useContentDetection), + mFeatures.test(Feature::kContentDetection) ? "on" : "off", mLayerHistory.dump().c_str()); { @@ -756,13 +687,8 @@ void Scheduler::dump(std::string& result) const { } } -void Scheduler::dumpVsync(std::string& s) const { - using base::StringAppendF; - - StringAppendF(&s, "VSyncReactor:\n"); - mVsyncSchedule.controller->dump(s); - StringAppendF(&s, "VSyncDispatch:\n"); - mVsyncSchedule.dispatch->dump(s); +void Scheduler::dumpVsync(std::string& out) const { + mVsyncSchedule->dump(out); } bool Scheduler::updateFrameRateOverrides( @@ -774,7 +700,7 @@ bool Scheduler::updateFrameRateOverrides( if (!consideredSignals.idle) { const auto frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(mFeatures.contentRequirements, + refreshRateConfigs->getFrameRateOverrides(mPolicy.contentRequirements, displayRefreshRate, consideredSignals); std::lock_guard lock(mFrameRateOverridesLock); if (!std::equal(mFrameRateOverridesByContent.begin(), mFrameRateOverridesByContent.end(), @@ -797,31 +723,30 @@ bool Scheduler::handleTimerStateChanged(T* currentState, T newState) { scheduler::RefreshRateConfigs::GlobalSignals consideredSignals; const auto refreshRateConfigs = holdRefreshRateConfigs(); { - std::lock_guard lock(mFeatureStateLock); + std::lock_guard lock(mPolicyLock); if (*currentState == newState) { return false; } *currentState = newState; newMode = calculateRefreshRateModeId(&consideredSignals); frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); - if (mFeatures.mode == newMode) { + if (mPolicy.mode == newMode) { // We don't need to change the display mode, but we might need to send an event // about a mode change, since it was suppressed due to a previous idleConsidered if (!consideredSignals.idle) { dispatchCachedReportedMode(); } } else { - mFeatures.mode = newMode; + mPolicy.mode = newMode; refreshRateChanged = true; } } if (refreshRateChanged) { - const RefreshRate& newRefreshRate = - refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); + const auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); mSchedulerCallback.changeRefreshRate(newRefreshRate, - consideredSignals.idle ? ModeEvent::None - : ModeEvent::Changed); + consideredSignals.idle ? DisplayModeEvent::None + : DisplayModeEvent::Changed); } if (frameRateOverridesChanged) { mSchedulerCallback.triggerOnFrameRateOverridesChanged(); @@ -838,27 +763,26 @@ DisplayModePtr Scheduler::calculateRefreshRateModeId( // If Display Power is not in normal operation we want to be in performance mode. When coming // back to normal mode, a grace period is given with DisplayPowerTimer. if (mDisplayPowerTimer && - (!mFeatures.isDisplayPowerStateNormal || - mFeatures.displayPowerTimer == TimerState::Reset)) { + (!mPolicy.isDisplayPowerStateNormal || mPolicy.displayPowerTimer == TimerState::Reset)) { return refreshRateConfigs->getMaxRefreshRateByPolicy().getMode(); } - const bool touchActive = mTouchTimer && mFeatures.touch == TouchState::Active; - const bool idle = mFeatures.idleTimer == TimerState::Expired; + const bool touchActive = mTouchTimer && mPolicy.touch == TouchState::Active; + const bool idle = mPolicy.idleTimer == TimerState::Expired; return refreshRateConfigs - ->getBestRefreshRate(mFeatures.contentRequirements, - {.touch = touchActive, .idle = idle}, consideredSignals) + ->getBestRefreshRate(mPolicy.contentRequirements, {.touch = touchActive, .idle = idle}, + consideredSignals) .getMode(); } DisplayModePtr Scheduler::getPreferredDisplayMode() { - std::lock_guard lock(mFeatureStateLock); + std::lock_guard lock(mPolicyLock); // Make sure that the default mode ID is first updated, before returned. - if (mFeatures.mode) { - mFeatures.mode = calculateRefreshRateModeId(); + if (mPolicy.mode) { + mPolicy.mode = calculateRefreshRateModeId(); } - return mFeatures.mode; + return mPolicy.mode; } void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) { @@ -915,8 +839,8 @@ void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverrid std::chrono::steady_clock::time_point Scheduler::getPreviousVsyncFrom( nsecs_t expectedPresentTime) const { const auto presentTime = std::chrono::nanoseconds(expectedPresentTime); - const auto vsyncPeriod = std::chrono::nanoseconds(mVsyncSchedule.tracker->currentPeriod()); + const auto vsyncPeriod = std::chrono::nanoseconds(mVsyncSchedule->getTracker().currentPeriod()); return std::chrono::steady_clock::time_point(presentTime - vsyncPeriod); } -} // namespace android +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 2a6de54e93..e127ff7371 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -31,40 +31,37 @@ #include #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" +#include + #include "EventThread.h" #include "LayerHistory.h" #include "MessageQueue.h" #include "OneShotTimer.h" #include "RefreshRateConfigs.h" #include "SchedulerUtils.h" +#include "VsyncSchedule.h" namespace android { -using namespace std::chrono_literals; -using scheduler::LayerHistory; - class FenceTime; class InjectVSyncSource; -class PredictedVsyncTracer; - -namespace scheduler { -class VsyncController; -class VSyncDispatch; -class VSyncTracker; -} // namespace scheduler namespace frametimeline { class TokenManager; } // namespace frametimeline +namespace scheduler { + struct ISchedulerCallback { // Indicates frame activity, i.e. whether commit and/or composite is taking place. enum class FrameHint { kNone, kActive }; + using RefreshRate = RefreshRateConfigs::RefreshRate; + using DisplayModeEvent = scheduler::DisplayModeEvent; + virtual void scheduleComposite(FrameHint) = 0; virtual void setVsyncEnabled(bool) = 0; - virtual void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&, - scheduler::RefreshRateConfigEvent) = 0; + virtual void changeRefreshRate(const RefreshRate&, DisplayModeEvent) = 0; virtual void kernelTimerChanged(bool expired) = 0; virtual void triggerOnFrameRateOverridesChanged() = 0; @@ -76,18 +73,10 @@ class Scheduler : impl::MessageQueue { using Impl = impl::MessageQueue; public: - using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; - using ModeEvent = scheduler::RefreshRateConfigEvent; - - struct Options { - // Whether to use content detection at all. - bool useContentDetection; - }; - - Scheduler(ICompositor&, ISchedulerCallback&, Options); + Scheduler(ICompositor&, ISchedulerCallback&, FeatureFlags); ~Scheduler(); - void createVsyncSchedule(bool supportKernelIdleTimer); + void createVsyncSchedule(FeatureFlags); void startTimers(); void run(); @@ -107,7 +96,6 @@ public: return std::move(future); } - using ConnectionHandle = scheduler::ConnectionHandle; ConnectionHandle createConnection(const char* connectionName, frametimeline::TokenManager*, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, @@ -119,7 +107,7 @@ public: sp getEventConnection(ConnectionHandle); void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected); - void onPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr) EXCLUDES(mFeatureStateLock); + void onPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr) EXCLUDES(mPolicyLock); void onNonPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr); void onScreenAcquired(ConnectionHandle); void onScreenReleased(ConnectionHandle); @@ -152,8 +140,7 @@ public: // VsyncController detected that the vsync period changed, and false otherwise. void addResyncSample(nsecs_t timestamp, std::optional hwcVsyncPeriod, bool* periodFlushed); - void addPresentFence(const std::shared_ptr&); - void setIgnorePresentFences(bool ignore); + void addPresentFence(std::shared_ptr); // Layers are registered on creation, and unregistered when the weak reference expires. void registerLayer(Layer*); @@ -172,7 +159,7 @@ public: void setDisplayPowerState(bool normal); - scheduler::VSyncDispatch& getVsyncDispatch() { return *mVsyncSchedule.dispatch; } + VSyncDispatch& getVsyncDispatch() { return mVsyncSchedule->getDispatch(); } // Returns true if a given vsync timestamp is considered valid vsync // for a given uid @@ -211,7 +198,7 @@ public: std::optional getFrameRateOverride(uid_t uid) const EXCLUDES(mRefreshRateConfigsLock, mFrameRateOverridesLock); - void setRefreshRateConfigs(std::shared_ptr refreshRateConfigs) + void setRefreshRateConfigs(std::shared_ptr refreshRateConfigs) EXCLUDES(mRefreshRateConfigsLock) { // We need to stop the idle timer on the previous RefreshRateConfigs instance // and cleanup the scheduler's state before we switch to the other RefreshRateConfigs. @@ -220,8 +207,8 @@ public: if (mRefreshRateConfigs) mRefreshRateConfigs->stopIdleTimer(); } { - std::scoped_lock lock(mFeatureStateLock); - mFeatures = {}; + std::scoped_lock lock(mPolicyLock); + mPolicy = {}; } { std::scoped_lock lock(mRefreshRateConfigsLock); @@ -251,18 +238,10 @@ private: using FrameHint = ISchedulerCallback::FrameHint; - // In order to make sure that the features don't override themselves, we need a state machine - // to keep track which feature requested the config change. enum class ContentDetectionState { Off, On }; enum class TimerState { Reset, Expired }; enum class TouchState { Inactive, Active }; - struct VsyncSchedule { - std::unique_ptr controller; - std::unique_ptr tracker; - std::unique_ptr dispatch; - }; - // Create a connection on the given EventThread. ConnectionHandle createConnection(std::unique_ptr); sp createConnectionInternal( @@ -284,19 +263,17 @@ private: // selection were initialized, prioritizes them, and calculates the DisplayModeId // for the suggested refresh rate. DisplayModePtr calculateRefreshRateModeId( - scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals = nullptr) - REQUIRES(mFeatureStateLock); + RefreshRateConfigs::GlobalSignals* consideredSignals = nullptr) REQUIRES(mPolicyLock); - void dispatchCachedReportedMode() REQUIRES(mFeatureStateLock) EXCLUDES(mRefreshRateConfigsLock); - bool updateFrameRateOverrides(scheduler::RefreshRateConfigs::GlobalSignals consideredSignals, - Fps displayRefreshRate) REQUIRES(mFeatureStateLock) - EXCLUDES(mFrameRateOverridesLock); + void dispatchCachedReportedMode() REQUIRES(mPolicyLock) EXCLUDES(mRefreshRateConfigsLock); + bool updateFrameRateOverrides(RefreshRateConfigs::GlobalSignals, Fps displayRefreshRate) + REQUIRES(mPolicyLock) EXCLUDES(mFrameRateOverridesLock); impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const EXCLUDES(mRefreshRateConfigsLock); impl::EventThread::GetVsyncPeriodFunction makeGetVsyncPeriodFunction() const; - std::shared_ptr holdRefreshRateConfigs() const + std::shared_ptr holdRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) { std::scoped_lock lock(mRefreshRateConfigsLock); return mRefreshRateConfigs; @@ -322,66 +299,63 @@ private: std::atomic mLastResyncTime = 0; - const Options mOptions; - VsyncSchedule mVsyncSchedule; + const FeatureFlags mFeatures; + std::optional mVsyncSchedule; // Used to choose refresh rate if content detection is enabled. LayerHistory mLayerHistory; // Timer used to monitor touch events. - std::optional mTouchTimer; + std::optional mTouchTimer; // Timer used to monitor display power mode. - std::optional mDisplayPowerTimer; + std::optional mDisplayPowerTimer; ISchedulerCallback& mSchedulerCallback; - // In order to make sure that the features don't override themselves, we need a state machine - // to keep track which feature requested the config change. - mutable std::mutex mFeatureStateLock; + mutable std::mutex mPolicyLock; struct { + // Policy for choosing the display mode. + LayerHistory::Summary contentRequirements; TimerState idleTimer = TimerState::Reset; TouchState touch = TouchState::Inactive; TimerState displayPowerTimer = TimerState::Expired; + bool isDisplayPowerStateNormal = true; + // Chosen display mode. DisplayModePtr mode; - LayerHistory::Summary contentRequirements; - - bool isDisplayPowerStateNormal = true; - // Used to cache the last parameters of onPrimaryDisplayModeChanged struct ModeChangedParams { ConnectionHandle handle; DisplayModePtr mode; }; + // Parameters for latest dispatch of mode change event. std::optional cachedModeChangedParams; - } mFeatures GUARDED_BY(mFeatureStateLock); + } mPolicy GUARDED_BY(mPolicyLock); mutable std::mutex mRefreshRateConfigsLock; - std::shared_ptr mRefreshRateConfigs - GUARDED_BY(mRefreshRateConfigsLock); + std::shared_ptr mRefreshRateConfigs GUARDED_BY(mRefreshRateConfigsLock); std::mutex mVsyncTimelineLock; std::optional mLastVsyncPeriodChangeTimeline GUARDED_BY(mVsyncTimelineLock); static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms; - std::unique_ptr mPredictedVsyncTracer; - // The frame rate override lists need their own mutex as they are being read // by SurfaceFlinger, Scheduler and EventThread (as a callback) to prevent deadlocks mutable std::mutex mFrameRateOverridesLock; // mappings between a UID and a preferred refresh rate that this app would // run at. - scheduler::RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesByContent + RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesByContent GUARDED_BY(mFrameRateOverridesLock); - scheduler::RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesFromBackdoor + RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesFromBackdoor GUARDED_BY(mFrameRateOverridesLock); // Keeps track of whether the screen is acquired for debug std::atomic mScreenAcquired = false; }; +} // namespace scheduler } // namespace android diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp index ee973f718a..1c9de1c452 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp @@ -47,7 +47,7 @@ VSyncReactor::VSyncReactor(std::unique_ptr clock, VSyncTracker& tracker, VSyncReactor::~VSyncReactor() = default; -bool VSyncReactor::addPresentFence(const std::shared_ptr& fence) { +bool VSyncReactor::addPresentFence(std::shared_ptr fence) { if (!fence) { return false; } @@ -80,7 +80,7 @@ bool VSyncReactor::addPresentFence(const std::shared_ptr& fe if (mPendingLimit == mUnfiredFences.size()) { mUnfiredFences.erase(mUnfiredFences.begin()); } - mUnfiredFences.push_back(fence); + mUnfiredFences.push_back(std::move(fence)); } else { timestampAccepted &= mTracker.addVsyncTimestamp(signalTime); } diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h index 449d4c3bee..a9d536be28 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.h +++ b/services/surfaceflinger/Scheduler/VSyncReactor.h @@ -37,7 +37,7 @@ public: bool supportKernelIdleTimer); ~VSyncReactor(); - bool addPresentFence(const std::shared_ptr& fence) final; + bool addPresentFence(std::shared_ptr) final; void setIgnorePresentFences(bool ignore) final; void startPeriodTransition(nsecs_t period) final; diff --git a/services/surfaceflinger/Scheduler/VsyncController.h b/services/surfaceflinger/Scheduler/VsyncController.h index 0f0df222f4..59f65372a9 100644 --- a/services/surfaceflinger/Scheduler/VsyncController.h +++ b/services/surfaceflinger/Scheduler/VsyncController.h @@ -17,19 +17,15 @@ #pragma once #include +#include +#include #include #include #include -#include - -#include - namespace android::scheduler { -class FenceTime; - class VsyncController { public: virtual ~VsyncController(); @@ -43,7 +39,7 @@ public: * an accurate prediction, * False otherwise */ - virtual bool addPresentFence(const std::shared_ptr&) = 0; + virtual bool addPresentFence(std::shared_ptr) = 0; /* * Adds a hw sync timestamp to the model. The controller will use the timestamp diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp new file mode 100644 index 0000000000..77d1223aeb --- /dev/null +++ b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp @@ -0,0 +1,113 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "VsyncSchedule.h" + +#include "Timer.h" +#include "VSyncDispatchTimerQueue.h" +#include "VSyncPredictor.h" +#include "VSyncReactor.h" + +#include "../TracedOrdinal.h" + +namespace android::scheduler { + +class VsyncSchedule::PredictedVsyncTracer { + // Invoked from the thread of the VsyncDispatch owned by this VsyncSchedule. + constexpr auto makeVsyncCallback() { + return [this](nsecs_t, nsecs_t, nsecs_t) { + mParity = !mParity; + schedule(); + }; + } + +public: + explicit PredictedVsyncTracer(VsyncDispatch& dispatch) + : mRegistration(dispatch, makeVsyncCallback(), __func__) { + schedule(); + } + +private: + void schedule() { mRegistration.schedule({0, 0, 0}); } + + TracedOrdinal mParity = {"VSYNC-predicted", 0}; + VSyncCallbackRegistration mRegistration; +}; + +VsyncSchedule::VsyncSchedule(FeatureFlags features) + : mTracker(createTracker()), + mDispatch(createDispatch(*mTracker)), + mController(createController(*mTracker, features)) { + if (features.test(Feature::kTracePredictedVsync)) { + mTracer = std::make_unique(*mDispatch); + } +} + +VsyncSchedule::VsyncSchedule(TrackerPtr tracker, DispatchPtr dispatch, ControllerPtr controller) + : mTracker(std::move(tracker)), + mDispatch(std::move(dispatch)), + mController(std::move(controller)) {} + +VsyncSchedule::VsyncSchedule(VsyncSchedule&&) = default; +VsyncSchedule::~VsyncSchedule() = default; + +void VsyncSchedule::dump(std::string& out) const { + out.append("VsyncController:\n"); + mController->dump(out); + + out.append("VsyncDispatch:\n"); + mDispatch->dump(out); +} + +VsyncSchedule::TrackerPtr VsyncSchedule::createTracker() { + // TODO(b/144707443): Tune constants. + constexpr nsecs_t kInitialPeriod = (60_Hz).getPeriodNsecs(); + constexpr size_t kHistorySize = 20; + constexpr size_t kMinSamplesForPrediction = 6; + constexpr uint32_t kDiscardOutlierPercent = 20; + + return std::make_unique(kInitialPeriod, kHistorySize, kMinSamplesForPrediction, + kDiscardOutlierPercent); +} + +VsyncSchedule::DispatchPtr VsyncSchedule::createDispatch(VsyncTracker& tracker) { + using namespace std::chrono_literals; + + // TODO(b/144707443): Tune constants. + constexpr std::chrono::nanoseconds kGroupDispatchWithin = 500us; + constexpr std::chrono::nanoseconds kSnapToSameVsyncWithin = 3ms; + + return std::make_unique(std::make_unique(), tracker, + kGroupDispatchWithin.count(), + kSnapToSameVsyncWithin.count()); +} + +VsyncSchedule::ControllerPtr VsyncSchedule::createController(VsyncTracker& tracker, + FeatureFlags features) { + // TODO(b/144707443): Tune constants. + constexpr size_t kMaxPendingFences = 20; + const bool hasKernelIdleTimer = features.test(Feature::kKernelIdleTimer); + + auto reactor = std::make_unique(std::make_unique(), tracker, + kMaxPendingFences, hasKernelIdleTimer); + + reactor->setIgnorePresentFences(!features.test(Feature::kPresentFences)); + return reactor; +} + +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.h b/services/surfaceflinger/Scheduler/VsyncSchedule.h new file mode 100644 index 0000000000..0d9b114875 --- /dev/null +++ b/services/surfaceflinger/Scheduler/VsyncSchedule.h @@ -0,0 +1,75 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +namespace android::scheduler { + +// TODO(b/185535769): Rename classes, and remove aliases. +class VSyncDispatch; +class VSyncTracker; + +class VsyncController; +using VsyncDispatch = VSyncDispatch; +using VsyncTracker = VSyncTracker; + +// Schedule that synchronizes to hardware VSYNC of a physical display. +class VsyncSchedule { +public: + explicit VsyncSchedule(FeatureFlags); + VsyncSchedule(VsyncSchedule&&); + ~VsyncSchedule(); + + // TODO(b/185535769): Hide behind API. + const VsyncTracker& getTracker() const { return *mTracker; } + VsyncTracker& getTracker() { return *mTracker; } + VsyncController& getController() { return *mController; } + + // TODO(b/185535769): Remove once VsyncSchedule owns all registrations. + VsyncDispatch& getDispatch() { return *mDispatch; } + + void dump(std::string&) const; + +private: + friend class TestableScheduler; + + using TrackerPtr = std::unique_ptr; + using DispatchPtr = std::unique_ptr; + using ControllerPtr = std::unique_ptr; + + // For tests. + VsyncSchedule(TrackerPtr, DispatchPtr, ControllerPtr); + + static TrackerPtr createTracker(); + static DispatchPtr createDispatch(VsyncTracker&); + static ControllerPtr createController(VsyncTracker&, FeatureFlags); + + class PredictedVsyncTracer; + using TracerPtr = std::unique_ptr; + + // Effectively const except in move constructor. + TrackerPtr mTracker; + DispatchPtr mDispatch; + ControllerPtr mController; + TracerPtr mTracer; +}; + +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Features.h b/services/surfaceflinger/Scheduler/include/scheduler/Features.h new file mode 100644 index 0000000000..0e96678420 --- /dev/null +++ b/services/surfaceflinger/Scheduler/include/scheduler/Features.h @@ -0,0 +1,34 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +namespace android::scheduler { + +enum class Feature : std::uint8_t { + kPresentFences = 0b1, + kKernelIdleTimer = 0b10, + kContentDetection = 0b100, + kTracePredictedVsync = 0b1000, +}; + +using FeatureFlags = Flags; + +} // namespace android::scheduler diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e497d95306..3860901edb 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1200,7 +1200,7 @@ void SurfaceFlinger::updateInternalStateWithChangedMode() { mRefreshRateStats->setRefreshRate(refreshRate); updatePhaseConfiguration(refreshRate); - if (upcomingModeInfo.event != Scheduler::ModeEvent::None) { + if (upcomingModeInfo.event != DisplayModeEvent::None) { mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, upcomingModeInfo.mode); } } @@ -3099,7 +3099,7 @@ void SurfaceFlinger::updateCursorAsync() { mCompositionEngine->updateCursorAsync(refreshArgs); } -void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate, Scheduler::ModeEvent event) { +void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate, DisplayModeEvent event) { // If this is called from the main thread mStateLock must be locked before // Currently the only way to call this function from the main thread is from // Scheduler::chooseRefreshRateForContent @@ -3147,17 +3147,32 @@ void SurfaceFlinger::initScheduler(const sp& display) { mVsyncConfiguration = getFactory().createVsyncConfiguration(currRefreshRate); mVsyncModulator = sp::make(mVsyncConfiguration->getCurrentConfigs()); - const Scheduler::Options options = { - .useContentDetection = sysprop::use_content_detection_for_refresh_rate(false)}; + using Feature = scheduler::Feature; + scheduler::FeatureFlags features; - mScheduler = std::make_unique(static_cast(*this), - static_cast(*this), options); + if (sysprop::use_content_detection_for_refresh_rate(false)) { + features |= Feature::kContentDetection; + } + if (base::GetBoolProperty("debug.sf.show_predicted_vsync"s, false)) { + features |= Feature::kTracePredictedVsync; + } + if (!base::GetBoolProperty("debug.sf.vsync_reactor_ignore_present_fences"s, false) && + !getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) { + features |= Feature::kPresentFences; + } + + mScheduler = std::make_unique(static_cast(*this), + static_cast(*this), + features); { auto configs = display->holdRefreshRateConfigs(); - mScheduler->createVsyncSchedule(configs->supportsKernelIdleTimer()); + if (configs->supportsKernelIdleTimer()) { + features |= Feature::kKernelIdleTimer; + } + + mScheduler->createVsyncSchedule(features); mScheduler->setRefreshRateConfigs(std::move(configs)); } - setVsyncEnabled(false); mScheduler->startTimers(); @@ -3190,11 +3205,6 @@ void SurfaceFlinger::initScheduler(const sp& display) { // classes from EventThread, and there should be no run-time binder cost // anyway since there are no connected apps at this point. mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, display->getActiveMode()); - static auto ignorePresentFences = - base::GetBoolProperty("debug.sf.vsync_reactor_ignore_present_fences"s, false); - mScheduler->setIgnorePresentFences( - ignorePresentFences || - getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE)); } void SurfaceFlinger::updatePhaseConfiguration(const Fps& refreshRate) { @@ -3818,10 +3828,11 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin clientStateFlags |= setClientStateLocked(frameTimelineInfo, state, desiredPresentTime, isAutoTimestamp, postTime, permissions); if ((flags & eAnimation) && state.state.surface) { - if (const auto layer = fromHandle(state.state.surface).promote(); layer) { + if (const auto layer = fromHandle(state.state.surface).promote()) { + using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; mScheduler->recordLayerHistory(layer.get(), isAutoTimestamp ? 0 : desiredPresentTime, - LayerHistory::LayerUpdateType::AnimationTX); + LayerUpdateType::AnimationTX); } } } @@ -6478,7 +6489,7 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( if (display->refreshRateConfigs().isModeAllowed(preferredDisplayMode->getId())) { ALOGV("switching to Scheduler preferred display mode %d", preferredDisplayMode->getId().value()); - setDesiredActiveMode({preferredDisplayMode, Scheduler::ModeEvent::Changed}); + setDesiredActiveMode({preferredDisplayMode, DisplayModeEvent::Changed}); } else { LOG_ALWAYS_FATAL("Desired display mode not allowed: %d", preferredDisplayMode->getId().value()); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 05c058b9af..eb934b6b16 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -165,7 +165,7 @@ class SurfaceFlinger : public BnSurfaceComposer, private IBinder::DeathRecipient, private HWC2::ComposerCallback, private ICompositor, - private ISchedulerCallback { + private scheduler::ISchedulerCallback { public: struct SkipInitializationTag {}; @@ -356,7 +356,6 @@ private: friend class TransactionApplicationTest; friend class TunnelModeEnabledReporterTest; - using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; using VsyncModulator = scheduler::VsyncModulator; using TransactionSchedule = scheduler::TransactionSchedule; using TraverseLayersFunction = std::function; @@ -643,7 +642,7 @@ private: // Toggles hardware VSYNC by calling into HWC. void setVsyncEnabled(bool) override; // Initiates a refresh rate change to be applied on commit. - void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override; + void changeRefreshRate(const RefreshRate&, DisplayModeEvent) override; // Called when kernel idle timer has expired. Used to update the refresh rate overlay. void kernelTimerChanged(bool expired) override; // Called when the frame rate override list changed to trigger an event. @@ -1261,7 +1260,7 @@ private: /* * Scheduler */ - std::unique_ptr mScheduler; + std::unique_ptr mScheduler; scheduler::ConnectionHandle mAppConnectionHandle; scheduler::ConnectionHandle mSfConnectionHandle; diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index e509cc9385..6153e8e354 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -42,16 +42,12 @@ class HWComposer; class IGraphicBufferConsumer; class IGraphicBufferProducer; class Layer; -class MessageQueue; -class Scheduler; class StartPropertySetThread; class SurfaceFlinger; class SurfaceInterceptor; class TimeStats; struct DisplayDeviceCreationArgs; -struct ICompositor; -struct ISchedulerCallback; struct LayerCreationArgs; namespace compositionengine { diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 8d2c078305..eb5f31e796 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -138,7 +138,7 @@ public: .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - constexpr ISchedulerCallback* kCallback = nullptr; + constexpr scheduler::ISchedulerCallback* kCallback = nullptr; constexpr bool kHasMultipleConfigs = true; mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), std::move(eventThread), std::move(sfEventThread), kCallback, diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp index d4cfbbbe0c..5a0033ea7e 100644 --- a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp @@ -29,7 +29,7 @@ using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjec class InitiateModeChangeTest : public DisplayTransactionTest { public: - using Event = scheduler::RefreshRateConfigEvent; + using Event = scheduler::DisplayModeEvent; void SetUp() override { injectFakeBufferQueueFactory(); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index de5e9dfb97..0a3437aab9 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -121,7 +121,7 @@ public: mock::VsyncController* mVsyncController = new mock::VsyncController; mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker; - mock::SchedulerCallback mSchedulerCallback; + scheduler::mock::SchedulerCallback mSchedulerCallback; mock::EventThread* mEventThread = new mock::EventThread; mock::EventThread* mSFEventThread = new mock::EventThread; diff --git a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp index cd2fc7426e..bb1f4328b5 100644 --- a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp +++ b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp @@ -17,6 +17,8 @@ #undef LOG_TAG #define LOG_TAG "FpsReporterTest" +#include + #include #include #include @@ -36,6 +38,8 @@ namespace android { +using namespace std::chrono_literals; + using testing::_; using testing::DoAll; using testing::Mock; diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 4993a2d8bc..00687ad4b6 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -38,9 +38,9 @@ using testing::_; using testing::Return; using testing::ReturnRef; -namespace android { +namespace android::scheduler { -namespace scheduler { +using MockLayer = android::mock::MockLayer; class LayerHistoryTest : public testing::Test { protected: @@ -93,12 +93,12 @@ protected: } } - auto createLayer() { return sp(new mock::MockLayer(mFlinger.flinger())); } + auto createLayer() { return sp::make(mFlinger.flinger()); } auto createLayer(std::string name) { - return sp(new mock::MockLayer(mFlinger.flinger(), std::move(name))); + return sp::make(mFlinger.flinger(), std::move(name)); } - void recordFramesAndExpect(const sp& layer, nsecs_t& time, Fps frameRate, + void recordFramesAndExpect(const sp& layer, nsecs_t& time, Fps frameRate, Fps desiredRefreshRate, int numFrames) { LayerHistory::Summary summary; for (int i = 0; i < numFrames; i++) { @@ -768,8 +768,7 @@ INSTANTIATE_TEST_CASE_P(LeapYearTests, LayerHistoryTestParameterized, ::testing::Values(1s, 2s, 3s, 4s, 5s)); } // namespace -} // namespace scheduler -} // namespace android +} // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index e558f3b700..a6fd378d3d 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -28,12 +28,16 @@ #include "mock/MockLayer.h" #include "mock/MockSchedulerCallback.h" +namespace android::scheduler { + using testing::_; using testing::Return; -namespace android { namespace { +using MockEventThread = android::mock::EventThread; +using MockLayer = android::mock::MockLayer; + constexpr PhysicalDisplayId PHYSICAL_DISPLAY_ID = PhysicalDisplayId::fromPort(255u); class SchedulerTest : public testing::Test { @@ -64,21 +68,21 @@ protected: .setGroup(0) .build(); - std::shared_ptr mConfigs = - std::make_shared(DisplayModes{mode60}, mode60->getId()); + std::shared_ptr mConfigs = + std::make_shared(DisplayModes{mode60}, mode60->getId()); mock::SchedulerCallback mSchedulerCallback; TestableScheduler* mScheduler = new TestableScheduler{mConfigs, mSchedulerCallback}; - Scheduler::ConnectionHandle mConnectionHandle; - mock::EventThread* mEventThread; + ConnectionHandle mConnectionHandle; + MockEventThread* mEventThread; sp mEventThreadConnection; TestableSurfaceFlinger mFlinger; }; SchedulerTest::SchedulerTest() { - auto eventThread = std::make_unique(); + auto eventThread = std::make_unique(); mEventThread = eventThread.get(); EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0)); @@ -98,7 +102,7 @@ SchedulerTest::SchedulerTest() { } // namespace TEST_F(SchedulerTest, invalidConnectionHandle) { - Scheduler::ConnectionHandle handle; + ConnectionHandle handle; const sp connection = mScheduler->createDisplayEventConnection(handle); @@ -155,7 +159,7 @@ TEST_F(SchedulerTest, validConnectionHandle) { TEST_F(SchedulerTest, chooseRefreshRateForContentIsNoopWhenModeSwitchingIsNotSupported) { // The layer is registered at creation time and deregistered at destruction time. - sp layer = sp::make(mFlinger.flinger()); + sp layer = sp::make(mFlinger.flinger()); // recordLayerHistory should be a noop ASSERT_EQ(0u, mScheduler->getNumActiveLayers()); @@ -174,24 +178,22 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentIsNoopWhenModeSwitchingIsNotSup TEST_F(SchedulerTest, updateDisplayModes) { ASSERT_EQ(0u, mScheduler->layerHistorySize()); - sp layer = sp::make(mFlinger.flinger()); + sp layer = sp::make(mFlinger.flinger()); ASSERT_EQ(1u, mScheduler->layerHistorySize()); mScheduler->setRefreshRateConfigs( - std::make_shared(DisplayModes{mode60, mode120}, - mode60->getId())); + std::make_shared(DisplayModes{mode60, mode120}, mode60->getId())); ASSERT_EQ(0u, mScheduler->getNumActiveLayers()); mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer); ASSERT_EQ(1u, mScheduler->getNumActiveLayers()); } -TEST_F(SchedulerTest, testDispatchCachedReportedMode) { - // If the optional fields are cleared, the function should return before - // onModeChange is called. - mScheduler->clearOptionalFieldsInFeatures(); - EXPECT_NO_FATAL_FAILURE(mScheduler->dispatchCachedReportedMode()); +TEST_F(SchedulerTest, dispatchCachedReportedMode) { + mScheduler->clearCachedReportedMode(); + EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0); + EXPECT_NO_FATAL_FAILURE(mScheduler->dispatchCachedReportedMode()); } TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) { @@ -203,7 +205,7 @@ TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) { // If the handle is incorrect, the function should return before // onModeChange is called. - Scheduler::ConnectionHandle invalidHandle = {.id = 123}; + ConnectionHandle invalidHandle = {.id = 123}; EXPECT_NO_FATAL_FAILURE(mScheduler->onNonPrimaryDisplayModeChanged(invalidHandle, mode)); EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0); } @@ -224,10 +226,9 @@ MATCHER(Is120Hz, "") { TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { mScheduler->setRefreshRateConfigs( - std::make_shared(DisplayModes{mode60, mode120}, - mode60->getId())); + std::make_shared(DisplayModes{mode60, mode120}, mode60->getId())); - sp layer = sp::make(mFlinger.flinger()); + sp layer = sp::make(mFlinger.flinger()); mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer); @@ -241,4 +242,4 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { mScheduler->chooseRefreshRateForContent(); } -} // namespace android +} // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index eed62a70c3..fe5f9e0717 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -48,6 +48,8 @@ using android::Hwc2::IComposerClient; using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; +using scheduler::LayerHistory; + using FrameRate = Layer::FrameRate; using FrameRateCompatibility = Layer::FrameRateCompatibility; diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp index 69e0501bd6..ec7e8a7f82 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp @@ -17,6 +17,9 @@ #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" +#include +#include + #include "DisplayTransactionTestHelpers.h" #include @@ -27,6 +30,8 @@ namespace { using android::hardware::power::Boost; TEST_F(DisplayTransactionTest, notifyPowerBoostNotifiesTouchEvent) { + using namespace std::chrono_literals; + mFlinger.scheduler()->replaceTouchTimer(100); std::this_thread::sleep_for(10ms); // wait for callback to be triggered EXPECT_TRUE(mFlinger.scheduler()->isTouchActive()); // Starting timer activates touch @@ -47,4 +52,4 @@ TEST_F(DisplayTransactionTest, notifyPowerBoostNotifiesTouchEvent) { } } // namespace -} // namespace android \ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 9d1fc981aa..dabd2d2cc2 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -28,22 +28,20 @@ #include "mock/MockVSyncTracker.h" #include "mock/MockVsyncController.h" -namespace android { +namespace android::scheduler { class TestableScheduler : public Scheduler, private ICompositor { public: - TestableScheduler(std::shared_ptr configs, - ISchedulerCallback& callback) + TestableScheduler(std::shared_ptr configs, ISchedulerCallback& callback) : TestableScheduler(std::make_unique(), std::make_unique(), std::move(configs), callback) {} - TestableScheduler(std::unique_ptr vsyncController, - std::unique_ptr vsyncTracker, - std::shared_ptr configs, - ISchedulerCallback& callback) - : Scheduler(*this, callback, {.useContentDetection = true}) { - mVsyncSchedule = {std::move(vsyncController), std::move(vsyncTracker), nullptr}; + TestableScheduler(std::unique_ptr controller, + std::unique_ptr tracker, + std::shared_ptr configs, ISchedulerCallback& callback) + : Scheduler(*this, callback, Feature::kContentDetection) { + mVsyncSchedule.emplace(VsyncSchedule(std::move(tracker), nullptr, std::move(controller))); setRefreshRateConfigs(std::move(configs)); ON_CALL(*this, postMessage).WillByDefault([](sp&& handler) { @@ -86,33 +84,24 @@ public: } bool isTouchActive() { - std::lock_guard lock(mFeatureStateLock); - return mFeatures.touch == Scheduler::TouchState::Active; + std::lock_guard lock(mPolicyLock); + return mPolicy.touch == Scheduler::TouchState::Active; } void dispatchCachedReportedMode() { - std::lock_guard lock(mFeatureStateLock); + std::lock_guard lock(mPolicyLock); return Scheduler::dispatchCachedReportedMode(); } - void clearOptionalFieldsInFeatures() { - std::lock_guard lock(mFeatureStateLock); - mFeatures.cachedModeChangedParams.reset(); + void clearCachedReportedMode() { + std::lock_guard lock(mPolicyLock); + mPolicy.cachedModeChangedParams.reset(); } void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) { return Scheduler::onNonPrimaryDisplayModeChanged(handle, mode); } - ~TestableScheduler() { - // All these pointer and container clears help ensure that GMock does - // not report a leaked object, since the Scheduler instance may - // still be referenced by something despite our best efforts to destroy - // it after each test is done. - mVsyncSchedule.controller.reset(); - mConnections.clear(); - } - private: // ICompositor overrides: bool commit(nsecs_t, int64_t, nsecs_t) override { return false; } @@ -120,4 +109,4 @@ private: void sample() override {} }; -} // namespace android +} // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 4c5789e47f..4473e01c2b 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -169,12 +169,12 @@ public: } // namespace surfaceflinger::test -class TestableSurfaceFlinger final : private ISchedulerCallback { +class TestableSurfaceFlinger final : private scheduler::ISchedulerCallback { public: using HotplugEvent = SurfaceFlinger::HotplugEvent; SurfaceFlinger* flinger() { return mFlinger.get(); } - TestableScheduler* scheduler() { return mScheduler; } + scheduler::TestableScheduler* scheduler() { return mScheduler; } // Extend this as needed for accessing SurfaceFlinger private (and public) // functions. @@ -197,7 +197,8 @@ public: std::unique_ptr vsyncTracker, std::unique_ptr appEventThread, std::unique_ptr sfEventThread, - ISchedulerCallback* callback = nullptr, bool hasMultipleModes = false) { + scheduler::ISchedulerCallback* callback = nullptr, + bool hasMultipleModes = false) { DisplayModes modes{DisplayMode::Builder(0) .setId(DisplayModeId(0)) .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0)) @@ -224,17 +225,18 @@ public: std::make_unique(*mFlinger->mTimeStats, currFps, /*powerMode=*/hal::PowerMode::OFF); - mScheduler = new TestableScheduler(std::move(vsyncController), std::move(vsyncTracker), - mRefreshRateConfigs, *(callback ?: this)); + mScheduler = new scheduler::TestableScheduler(std::move(vsyncController), + std::move(vsyncTracker), mRefreshRateConfigs, + *(callback ?: this)); mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread)); mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread)); resetScheduler(mScheduler); } - void resetScheduler(Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); } + void resetScheduler(scheduler::Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); } - TestableScheduler& mutableScheduler() const { return *mScheduler; } + scheduler::TestableScheduler& mutableScheduler() const { return *mScheduler; } using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction; void setCreateBufferQueueFunction(CreateBufferQueueFunction f) { @@ -759,13 +761,13 @@ public: private: void scheduleComposite(FrameHint) override {} void setVsyncEnabled(bool) override {} - void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override {} + void changeRefreshRate(const RefreshRate&, DisplayModeEvent) override {} void kernelTimerChanged(bool) override {} void triggerOnFrameRateOverridesChanged() {} surfaceflinger::test::Factory mFactory; sp mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization); - TestableScheduler* mScheduler = nullptr; + scheduler::TestableScheduler* mScheduler = nullptr; std::shared_ptr mRefreshRateConfigs; }; diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index ec19100c2b..16d4b59250 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -26,7 +26,7 @@ #include #include #include -#include "TestableScheduler.h" + #include "TestableSurfaceFlinger.h" #include "mock/MockEventThread.h" #include "mock/MockVsyncController.h" @@ -85,11 +85,8 @@ public: std::move(eventThread), std::move(sfEventThread)); } - TestableScheduler* mScheduler; TestableSurfaceFlinger mFlinger; - std::unique_ptr mEventThread = std::make_unique(); - mock::VsyncController* mVsyncController = new mock::VsyncController(); mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker(); mock::MockFence* mFenceUnsignaled = new mock::MockFence(); diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h index e241dc903f..849e3083c4 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h +++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h @@ -20,25 +20,22 @@ #include "Scheduler/Scheduler.h" -namespace android::mock { +namespace android::scheduler::mock { struct SchedulerCallback final : ISchedulerCallback { MOCK_METHOD(void, scheduleComposite, (FrameHint), (override)); - MOCK_METHOD1(setVsyncEnabled, void(bool)); - MOCK_METHOD2(changeRefreshRate, - void(const scheduler::RefreshRateConfigs::RefreshRate&, - scheduler::RefreshRateConfigEvent)); - MOCK_METHOD1(kernelTimerChanged, void(bool)); - MOCK_METHOD0(triggerOnFrameRateOverridesChanged, void()); + MOCK_METHOD(void, setVsyncEnabled, (bool), (override)); + MOCK_METHOD(void, changeRefreshRate, (const RefreshRate&, DisplayModeEvent), (override)); + MOCK_METHOD(void, kernelTimerChanged, (bool), (override)); + MOCK_METHOD(void, triggerOnFrameRateOverridesChanged, (), (override)); }; struct NoOpSchedulerCallback final : ISchedulerCallback { void scheduleComposite(FrameHint) override {} void setVsyncEnabled(bool) override {} - void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&, - scheduler::RefreshRateConfigEvent) override {} + void changeRefreshRate(const RefreshRate&, DisplayModeEvent) override {} void kernelTimerChanged(bool) override {} void triggerOnFrameRateOverridesChanged() {} }; -} // namespace android::mock +} // namespace android::scheduler::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h index 94d99665ce..314f681545 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h +++ b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h @@ -27,7 +27,7 @@ public: VsyncController(); ~VsyncController() override; - MOCK_METHOD1(addPresentFence, bool(const std::shared_ptr&)); + MOCK_METHOD(bool, addPresentFence, (std::shared_ptr), (override)); MOCK_METHOD3(addHwVsyncTimestamp, bool(nsecs_t, std::optional, bool*)); MOCK_METHOD1(startPeriodTransition, void(nsecs_t)); MOCK_METHOD1(setIgnorePresentFences, void(bool)); -- cgit v1.2.3-59-g8ed1b From 34eb9ca577d78524b992d2af367e23ce89a9f034 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 18 Nov 2021 15:23:23 -0800 Subject: SF: Introduce background task executor Extract logic to execute work outside of the main thread from TransactionCallbackInvoker so we can reuse the thread for other tasks that are not critical to drawing. Bug: 206380307 Test: presubmit Change-Id: I8128d2f333e3aab5639cd1200e820de39f0b3191 --- services/surfaceflinger/Android.bp | 1 + services/surfaceflinger/BackgroundExecutor.cpp | 65 ++++++++++++++++++++++ services/surfaceflinger/BackgroundExecutor.h | 42 ++++++++++++++ .../surfaceflinger/TransactionCallbackInvoker.cpp | 39 ++----------- .../surfaceflinger/TransactionCallbackInvoker.h | 9 --- 5 files changed, 113 insertions(+), 43 deletions(-) create mode 100644 services/surfaceflinger/BackgroundExecutor.cpp create mode 100644 services/surfaceflinger/BackgroundExecutor.h diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index fb42cc02eb..2a9e2e7f0d 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -144,6 +144,7 @@ cc_library_headers { filegroup { name: "libsurfaceflinger_sources", srcs: [ + "BackgroundExecutor.cpp", "BufferLayer.cpp", "BufferLayerConsumer.cpp", "BufferQueueLayer.cpp", diff --git a/services/surfaceflinger/BackgroundExecutor.cpp b/services/surfaceflinger/BackgroundExecutor.cpp new file mode 100644 index 0000000000..3663cdb0ec --- /dev/null +++ b/services/surfaceflinger/BackgroundExecutor.cpp @@ -0,0 +1,65 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "BackgroundExecutor" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include "BackgroundExecutor.h" + +namespace android { + +ANDROID_SINGLETON_STATIC_INSTANCE(BackgroundExecutor); + +BackgroundExecutor::BackgroundExecutor() : Singleton() { + mThread = std::thread([&]() { + bool done = false; + while (!done) { + std::vector> tasks; + { + std::unique_lock lock(mMutex); + mWorkAvailableCv.wait(lock, [&]() { return mDone || !mTasks.empty(); }); + tasks = std::move(mTasks); + mTasks.clear(); + done = mDone; + } // unlock mMutex + + for (auto& task : tasks) { + task(); + } + } + }); +} + +BackgroundExecutor::~BackgroundExecutor() { + { + std::unique_lock lock(mMutex); + mDone = true; + mWorkAvailableCv.notify_all(); + } + if (mThread.joinable()) { + mThread.join(); + } +} + +void BackgroundExecutor::execute(std::function task) { + std::unique_lock lock(mMutex); + mTasks.emplace_back(std::move(task)); + mWorkAvailableCv.notify_all(); +} + +} // namespace android \ No newline at end of file diff --git a/services/surfaceflinger/BackgroundExecutor.h b/services/surfaceflinger/BackgroundExecutor.h new file mode 100644 index 0000000000..6f6d305280 --- /dev/null +++ b/services/surfaceflinger/BackgroundExecutor.h @@ -0,0 +1,42 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace android { + +// Executes tasks off the main thread. +class BackgroundExecutor : public Singleton { +public: + BackgroundExecutor(); + ~BackgroundExecutor(); + void execute(std::function); + +private: + std::mutex mMutex; + std::condition_variable mWorkAvailableCv; + std::thread mThread; + bool mDone = false; + std::vector> mTasks; +}; + +} // namespace android diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index f3d46ea061..b705d9cf7b 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -24,6 +24,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "TransactionCallbackInvoker.h" +#include "BackgroundExecutor.h" #include @@ -49,31 +50,6 @@ static bool containsOnCommitCallbacks(const std::vector& callbacks) return !callbacks.empty() && callbacks.front().type == CallbackId::Type::ON_COMMIT; } -TransactionCallbackInvoker::TransactionCallbackInvoker() { - mThread = std::thread([&]() { - std::unique_lock lock(mCallbackThreadMutex); - - while (mKeepRunning) { - while (mCallbackThreadWork.size() > 0) { - mCallbackThreadWork.front()(); - mCallbackThreadWork.pop(); - } - mCallbackConditionVariable.wait(lock); - } - }); -} - -TransactionCallbackInvoker::~TransactionCallbackInvoker() { - { - std::unique_lock lock(mCallbackThreadMutex); - mKeepRunning = false; - mCallbackConditionVariable.notify_all(); - } - if (mThread.joinable()) { - mThread.join(); - } -} - void TransactionCallbackInvoker::addEmptyTransaction(const ListenerCallbacks& listenerCallbacks) { auto& [listener, callbackIds] = listenerCallbacks; auto& transactionStatsDeque = mCompletedTransactions[listener]; @@ -242,15 +218,10 @@ void TransactionCallbackInvoker::sendCallbacks(bool onCommitOnly) { // keep it as an IBinder due to consistency reasons: if we // interface_cast at the IPC boundary when reading a Parcel, // we get pointers that compare unequal in the SF process. - { - std::unique_lock lock(mCallbackThreadMutex); - mCallbackThreadWork.push( - [stats = std::move(listenerStats)]() { - interface_cast(stats.listener) - ->onTransactionCompleted(stats); - }); - mCallbackConditionVariable.notify_all(); - } + BackgroundExecutor::getInstance().execute([stats = std::move(listenerStats)]() { + interface_cast(stats.listener) + ->onTransactionCompleted(stats); + }); } } completedTransactionsItr++; diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index e203d41bd9..5ef54757d7 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -61,9 +61,6 @@ public: class TransactionCallbackInvoker { public: - TransactionCallbackInvoker(); - ~TransactionCallbackInvoker(); - status_t addCallbackHandles(const std::deque>& handles, const std::vector& jankData); status_t addOnCommitCallbackHandles(const std::deque>& handles, @@ -94,12 +91,6 @@ private: mCompletedTransactions; sp mPresentFence; - - std::mutex mCallbackThreadMutex; - std::condition_variable mCallbackConditionVariable; - std::thread mThread; - bool mKeepRunning = true; - std::queue> mCallbackThreadWork; }; } // namespace android -- cgit v1.2.3-59-g8ed1b From f5d0ea545aaea01d8d73ad97603619ec3874a2e7 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Sun, 26 Sep 2021 17:27:01 -0700 Subject: SF: Remove manual enum stringification Upgrade to scoped enums where applicable. Pull GameMode from TimeStats into libgui to plumb it as an enum rather than int32_t. Bug: 185536303 Test: libsurfaceflinger_unittest Change-Id: I81fdd24805757ef953484055ee867684eb94fecf --- libs/gui/include/gui/LayerMetadata.h | 10 + services/surfaceflinger/BufferLayer.cpp | 14 +- .../include/compositionengine/DisplaySurface.h | 11 +- .../CompositionEngine/src/RenderSurface.cpp | 19 +- .../CompositionEngine/tests/RenderSurfaceTest.cpp | 8 +- .../DisplayHardware/VirtualDisplaySurface.cpp | 242 ++++++++------------- .../DisplayHardware/VirtualDisplaySurface.h | 64 +++--- .../surfaceflinger/FrameTimeline/FrameTimeline.cpp | 4 +- .../surfaceflinger/FrameTimeline/FrameTimeline.h | 9 +- services/surfaceflinger/Layer.cpp | 34 +-- services/surfaceflinger/Layer.h | 18 +- services/surfaceflinger/Scheduler/LayerInfo.cpp | 7 +- services/surfaceflinger/Scheduler/LayerInfo.h | 2 + .../Scheduler/RefreshRateConfigs.cpp | 35 +-- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 4 +- services/surfaceflinger/Scheduler/Timer.cpp | 31 +-- services/surfaceflinger/Scheduler/Timer.h | 13 +- .../Scheduler/include/scheduler/Seamlessness.h | 22 +- services/surfaceflinger/SurfaceFlinger.cpp | 7 +- services/surfaceflinger/TimeStats/TimeStats.cpp | 24 +- services/surfaceflinger/TimeStats/TimeStats.h | 26 +-- .../TimeStats/timestatsproto/TimeStatsHelper.cpp | 45 +--- .../include/timestatsproto/TimeStatsHelper.h | 27 +-- .../tests/unittests/CompositionTest.cpp | 4 +- .../tests/unittests/FrameTimelineTest.cpp | 15 +- .../tests/unittests/GameModeTest.cpp | 41 ++-- .../tests/unittests/RefreshRateConfigsTest.cpp | 5 +- .../tests/unittests/TimeStatsTest.cpp | 74 +++---- .../tests/unittests/mock/MockTimeStats.h | 16 +- 29 files changed, 346 insertions(+), 485 deletions(-) diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h index de14b3d785..27f4d379e9 100644 --- a/libs/gui/include/gui/LayerMetadata.h +++ b/libs/gui/include/gui/LayerMetadata.h @@ -59,4 +59,14 @@ struct LayerMetadata : public Parcelable { std::string itemToString(uint32_t key, const char* separator) const; }; +// Keep in sync with the GameManager.java constants. +enum class GameMode : int32_t { + Unsupported = 0, + Standard = 1, + Performance = 2, + Battery = 3, + + ftl_last = Battery +}; + } // namespace android diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 861d4963f7..490775faec 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -401,12 +401,13 @@ void BufferLayer::onPostComposition(const DisplayDevice* display, const Fps refreshRate = display->refreshRateConfigs().getCurrentRefreshRate().getFps(); const std::optional renderRate = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); + + const auto vote = frameRateToSetFrameRateVotePayload(mDrawingState.frameRate); + const auto gameMode = getGameMode(); + if (presentFence->isValid()) { mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence, - refreshRate, renderRate, - frameRateToSetFrameRateVotePayload( - mDrawingState.frameRate), - getGameMode()); + refreshRate, renderRate, vote, gameMode); mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber, presentFence, FrameTracer::FrameEvent::PRESENT_FENCE); @@ -417,10 +418,7 @@ void BufferLayer::onPostComposition(const DisplayDevice* display, // timestamp instead. const nsecs_t actualPresentTime = display->getRefreshTimestamp(); mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime, - refreshRate, renderRate, - frameRateToSetFrameRateVotePayload( - mDrawingState.frameRate), - getGameMode()); + refreshRate, renderRate, vote, gameMode); mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber, actualPresentTime, FrameTracer::FrameEvent::PRESENT_FENCE); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h index 4502eee97c..c553fce85d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h @@ -16,6 +16,8 @@ #pragma once +#include + #include #include #include @@ -47,13 +49,8 @@ public: // before composition takes place. The DisplaySurface can use the // composition type to decide how to manage the flow of buffers between // GPU and HWC for this frame. - enum CompositionType { - COMPOSITION_UNKNOWN = 0, - COMPOSITION_GPU = 1, - COMPOSITION_HWC = 2, - COMPOSITION_MIXED = COMPOSITION_GPU | COMPOSITION_HWC - }; - virtual status_t prepareFrame(CompositionType compositionType) = 0; + enum class CompositionType : uint8_t { Unknown = 0, Gpu = 0b1, Hwc = 0b10, Mixed = Gpu | Hwc }; + virtual status_t prepareFrame(CompositionType) = 0; // Inform the surface that GPU composition is complete for this frame, and // the surface should make sure that HWComposer has the correct buffer for diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index ef50870615..a19d23febf 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -127,19 +127,18 @@ status_t RenderSurface::beginFrame(bool mustRecompose) { } void RenderSurface::prepareFrame(bool usesClientComposition, bool usesDeviceComposition) { - DisplaySurface::CompositionType compositionType; - if (usesClientComposition && usesDeviceComposition) { - compositionType = DisplaySurface::COMPOSITION_MIXED; - } else if (usesClientComposition) { - compositionType = DisplaySurface::COMPOSITION_GPU; - } else if (usesDeviceComposition) { - compositionType = DisplaySurface::COMPOSITION_HWC; - } else { + const auto compositionType = [=] { + using CompositionType = DisplaySurface::CompositionType; + + if (usesClientComposition && usesDeviceComposition) return CompositionType::Mixed; + if (usesClientComposition) return CompositionType::Gpu; + if (usesDeviceComposition) return CompositionType::Hwc; + // Nothing to do -- when turning the screen off we get a frame like // this. Call it a HWC frame since we won't be doing any GPU work but // will do a prepare/set cycle. - compositionType = DisplaySurface::COMPOSITION_HWC; - } + return CompositionType::Hwc; + }(); if (status_t result = mDisplaySurface->prepareFrame(compositionType); result != NO_ERROR) { ALOGE("updateCompositionType failed for %s: %d (%s)", mDisplay.getName().c_str(), result, diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index 431cc93514..7c8e41b53e 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -201,28 +201,28 @@ TEST_F(RenderSurfaceTest, beginFrameAppliesChange) { */ TEST_F(RenderSurfaceTest, prepareFrameHandlesMixedComposition) { - EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_MIXED)) + EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::CompositionType::Mixed)) .WillOnce(Return(NO_ERROR)); mSurface.prepareFrame(true, true); } TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyGpuComposition) { - EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GPU)) + EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::CompositionType::Gpu)) .WillOnce(Return(NO_ERROR)); mSurface.prepareFrame(true, false); } TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyHwcComposition) { - EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC)) + EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::CompositionType::Hwc)) .WillOnce(Return(NO_ERROR)); mSurface.prepareFrame(false, true); } TEST_F(RenderSurfaceTest, prepareFrameHandlesNoComposition) { - EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC)) + EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::CompositionType::Hwc)) .WillOnce(Return(NO_ERROR)); mSurface.prepareFrame(false, false); diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 82a9ae2578..b4fb51f9d5 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -21,20 +21,18 @@ // #define LOG_NDEBUG 0 #include "VirtualDisplaySurface.h" -#include +#include #include "HWComposer.h" #include "SurfaceFlinger.h" +#include +#include #include #include #include #include -// --------------------------------------------------------------------------- -namespace android { -// --------------------------------------------------------------------------- - #define VDS_LOGE(msg, ...) ALOGE("[%s] " msg, \ mDisplayName.c_str(), ##__VA_ARGS__) #define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] " msg, \ @@ -42,20 +40,11 @@ namespace android { #define VDS_LOGV(msg, ...) ALOGV("[%s] " msg, \ mDisplayName.c_str(), ##__VA_ARGS__) -static const char* dbgCompositionTypeStr(compositionengine::DisplaySurface::CompositionType type) { - switch (type) { - case compositionengine::DisplaySurface::COMPOSITION_UNKNOWN: - return "UNKNOWN"; - case compositionengine::DisplaySurface::COMPOSITION_GPU: - return "GPU"; - case compositionengine::DisplaySurface::COMPOSITION_HWC: - return "HWC"; - case compositionengine::DisplaySurface::COMPOSITION_MIXED: - return "MIXED"; - default: - return ""; - } -} +#define UNSUPPORTED() \ + VDS_LOGE("%s: Invalid operation on virtual display", __func__); \ + return INVALID_OPERATION + +namespace android { VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, VirtualDisplayId displayId, const sp& sink, @@ -76,14 +65,10 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, VirtualDisplayId d mQueueBufferOutput(), mSinkBufferWidth(0), mSinkBufferHeight(0), - mCompositionType(COMPOSITION_UNKNOWN), mFbFence(Fence::NO_FENCE), mOutputFence(Fence::NO_FENCE), mFbProducerSlot(BufferQueue::INVALID_BUFFER_SLOT), mOutputProducerSlot(BufferQueue::INVALID_BUFFER_SLOT), - mDbgState(DBG_STATE_IDLE), - mDbgLastCompositionType(COMPOSITION_UNKNOWN), - mMustRecompose(false), mForceHwcCopy(SurfaceFlinger::useHwcForRgbToYuv) { mSource[SOURCE_SINK] = sink; mSource[SOURCE_SCRATCH] = bqProducer; @@ -131,9 +116,9 @@ status_t VirtualDisplaySurface::beginFrame(bool mustRecompose) { mMustRecompose = mustRecompose; - VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE, - "Unexpected beginFrame() in %s state", dbgStateStr()); - mDbgState = DBG_STATE_BEGUN; + VDS_LOGW_IF(mDebugState != DebugState::Idle, "Unexpected %s in %s state", __func__, + ftl::enum_string(mDebugState).c_str()); + mDebugState = DebugState::Begun; return refreshOutputBuffer(); } @@ -143,12 +128,12 @@ status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) { return NO_ERROR; } - VDS_LOGW_IF(mDbgState != DBG_STATE_BEGUN, - "Unexpected prepareFrame() in %s state", dbgStateStr()); - mDbgState = DBG_STATE_PREPARED; + VDS_LOGW_IF(mDebugState != DebugState::Begun, "Unexpected %s in %s state", __func__, + ftl::enum_string(mDebugState).c_str()); + mDebugState = DebugState::Prepared; mCompositionType = compositionType; - if (mForceHwcCopy && mCompositionType == COMPOSITION_GPU) { + if (mForceHwcCopy && mCompositionType == CompositionType::Gpu) { // Some hardware can do RGB->YUV conversion more efficiently in hardware // controlled by HWC than in hardware controlled by the video encoder. // Forcing GPU-composed frames to go through an extra copy by the HWC @@ -157,16 +142,16 @@ status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) { // // On the other hand, when the consumer prefers RGB or can consume RGB // inexpensively, this forces an unnecessary copy. - mCompositionType = COMPOSITION_MIXED; + mCompositionType = CompositionType::Mixed; } - if (mCompositionType != mDbgLastCompositionType) { - VDS_LOGV("prepareFrame: composition type changed to %s", - dbgCompositionTypeStr(mCompositionType)); - mDbgLastCompositionType = mCompositionType; + if (mCompositionType != mDebugLastCompositionType) { + VDS_LOGV("%s: composition type changed to %s", __func__, + toString(mCompositionType).c_str()); + mDebugLastCompositionType = mCompositionType; } - if (mCompositionType != COMPOSITION_GPU && + if (mCompositionType != CompositionType::Gpu && (mOutputFormat != mDefaultOutputFormat || mOutputUsage != GRALLOC_USAGE_HW_COMPOSER)) { // We must have just switched from GPU-only to MIXED or HWC // composition. Stop using the format and usage requested by the GPU @@ -191,33 +176,32 @@ status_t VirtualDisplaySurface::advanceFrame() { return NO_ERROR; } - if (mCompositionType == COMPOSITION_HWC) { - VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED, - "Unexpected advanceFrame() in %s state on HWC frame", - dbgStateStr()); + if (mCompositionType == CompositionType::Hwc) { + VDS_LOGW_IF(mDebugState != DebugState::Prepared, "Unexpected %s in %s state on HWC frame", + __func__, ftl::enum_string(mDebugState).c_str()); } else { - VDS_LOGW_IF(mDbgState != DBG_STATE_GPU_DONE, - "Unexpected advanceFrame() in %s state on GPU/MIXED frame", dbgStateStr()); + VDS_LOGW_IF(mDebugState != DebugState::GpuDone, + "Unexpected %s in %s state on GPU/MIXED frame", __func__, + ftl::enum_string(mDebugState).c_str()); } - mDbgState = DBG_STATE_HWC; + mDebugState = DebugState::Hwc; if (mOutputProducerSlot < 0 || - (mCompositionType != COMPOSITION_HWC && mFbProducerSlot < 0)) { + (mCompositionType != CompositionType::Hwc && mFbProducerSlot < 0)) { // Last chance bailout if something bad happened earlier. For example, // in a graphics API configuration, if the sink disappears then dequeueBuffer // will fail, the GPU driver won't queue a buffer, but SurfaceFlinger // will soldier on. So we end up here without a buffer. There should // be lots of scary messages in the log just before this. - VDS_LOGE("advanceFrame: no buffer, bailing out"); + VDS_LOGE("%s: no buffer, bailing out", __func__); return NO_MEMORY; } sp fbBuffer = mFbProducerSlot >= 0 ? mProducerBuffers[mFbProducerSlot] : sp(nullptr); sp outBuffer = mProducerBuffers[mOutputProducerSlot]; - VDS_LOGV("advanceFrame: fb=%d(%p) out=%d(%p)", - mFbProducerSlot, fbBuffer.get(), - mOutputProducerSlot, outBuffer.get()); + VDS_LOGV("%s: fb=%d(%p) out=%d(%p)", __func__, mFbProducerSlot, fbBuffer.get(), + mOutputProducerSlot, outBuffer.get()); const auto halDisplayId = HalVirtualDisplayId::tryCast(mDisplayId); LOG_FATAL_IF(!halDisplayId); @@ -245,16 +229,16 @@ void VirtualDisplaySurface::onFrameCommitted() { return; } - VDS_LOGW_IF(mDbgState != DBG_STATE_HWC, - "Unexpected onFrameCommitted() in %s state", dbgStateStr()); - mDbgState = DBG_STATE_IDLE; + VDS_LOGW_IF(mDebugState != DebugState::Hwc, "Unexpected %s in %s state", __func__, + ftl::enum_string(mDebugState).c_str()); + mDebugState = DebugState::Idle; sp retireFence = mHwc.getPresentFence(*halDisplayId); - if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) { + if (mCompositionType == CompositionType::Mixed && mFbProducerSlot >= 0) { // release the scratch buffer back to the pool Mutex::Autolock lock(mMutex); int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, mFbProducerSlot); - VDS_LOGV("onFrameCommitted: release scratch sslot=%d", sslot); + VDS_LOGV("%s: release scratch sslot=%d", __func__, sslot); addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], retireFence); releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot]); @@ -263,7 +247,7 @@ void VirtualDisplaySurface::onFrameCommitted() { if (mOutputProducerSlot >= 0) { int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot); QueueBufferOutput qbo; - VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot); + VDS_LOGV("%s: queue sink sslot=%d", __func__, sslot); if (mMustRecompose) { status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot, QueueBufferInput( @@ -308,8 +292,8 @@ status_t VirtualDisplaySurface::requestBuffer(int pslot, return mSource[SOURCE_SINK]->requestBuffer(pslot, outBuf); } - VDS_LOGW_IF(mDbgState != DBG_STATE_GPU, "Unexpected requestBuffer pslot=%d in %s state", pslot, - dbgStateStr()); + VDS_LOGW_IF(mDebugState != DebugState::Gpu, "Unexpected %s pslot=%d in %s state", __func__, + pslot, ftl::enum_string(mDebugState).c_str()); *outBuf = mProducerBuffers[pslot]; return NO_ERROR; @@ -334,8 +318,8 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source, if (result < 0) return result; int pslot = mapSource2ProducerSlot(source, *sslot); - VDS_LOGV("dequeueBuffer(%s): sslot=%d pslot=%d result=%d", - dbgSourceStr(source), *sslot, pslot, result); + VDS_LOGV("%s(%s): sslot=%d pslot=%d result=%d", __func__, ftl::enum_string(source).c_str(), + *sslot, pslot, result); uint64_t sourceBit = static_cast(source) << pslot; // reset producer slot reallocation flag @@ -363,10 +347,9 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source, mSource[source]->cancelBuffer(*sslot, *fence); return result; } - VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p fmt=%d usage=%#" PRIx64, - dbgSourceStr(source), pslot, mProducerBuffers[pslot].get(), - mProducerBuffers[pslot]->getPixelFormat(), - mProducerBuffers[pslot]->getUsage()); + VDS_LOGV("%s(%s): buffers[%d]=%p fmt=%d usage=%#" PRIx64, __func__, + ftl::enum_string(source).c_str(), pslot, mProducerBuffers[pslot].get(), + mProducerBuffers[pslot]->getPixelFormat(), mProducerBuffers[pslot]->getUsage()); // propagate reallocation to VDS consumer mProducerSlotNeedReallocation |= 1ULL << pslot; @@ -384,11 +367,11 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, uint outTimestamps); } - VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED, - "Unexpected dequeueBuffer() in %s state", dbgStateStr()); - mDbgState = DBG_STATE_GPU; + VDS_LOGW_IF(mDebugState != DebugState::Prepared, "Unexpected %s in %s state", __func__, + ftl::enum_string(mDebugState).c_str()); + mDebugState = DebugState::Gpu; - VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#" PRIx64, w, h, format, usage); + VDS_LOGV("%s %dx%d fmt=%d usage=%#" PRIx64, __func__, w, h, format, usage); status_t result = NO_ERROR; Source source = fbSourceForCompositionType(mCompositionType); @@ -401,7 +384,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, uint // will fail, the GPU driver won't queue a buffer, but SurfaceFlinger // will soldier on. So we end up here without a buffer. There should // be lots of scary messages in the log just before this. - VDS_LOGE("dequeueBuffer: no buffer, bailing out"); + VDS_LOGE("%s: no buffer, bailing out", __func__); return NO_MEMORY; } @@ -417,12 +400,11 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, uint (format != 0 && format != buf->getPixelFormat()) || (w != 0 && w != mSinkBufferWidth) || (h != 0 && h != mSinkBufferHeight)) { - VDS_LOGV("dequeueBuffer: dequeueing new output buffer: " - "want %dx%d fmt=%d use=%#" PRIx64 ", " - "have %dx%d fmt=%d use=%#" PRIx64, - w, h, format, usage, - mSinkBufferWidth, mSinkBufferHeight, - buf->getPixelFormat(), buf->getUsage()); + VDS_LOGV("%s: dequeueing new output buffer: " + "want %dx%d fmt=%d use=%#" PRIx64 ", " + "have %dx%d fmt=%d use=%#" PRIx64, + __func__, w, h, format, usage, mSinkBufferWidth, mSinkBufferHeight, + buf->getPixelFormat(), buf->getUsage()); mOutputFormat = format; mOutputUsage = usage; result = refreshOutputBuffer(); @@ -452,21 +434,16 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, uint return result; } -status_t VirtualDisplaySurface::detachBuffer(int /* slot */) { - VDS_LOGE("detachBuffer is not available for VirtualDisplaySurface"); - return INVALID_OPERATION; +status_t VirtualDisplaySurface::detachBuffer(int) { + UNSUPPORTED(); } -status_t VirtualDisplaySurface::detachNextBuffer( - sp* /* outBuffer */, sp* /* outFence */) { - VDS_LOGE("detachNextBuffer is not available for VirtualDisplaySurface"); - return INVALID_OPERATION; +status_t VirtualDisplaySurface::detachNextBuffer(sp*, sp*) { + UNSUPPORTED(); } -status_t VirtualDisplaySurface::attachBuffer(int* /* outSlot */, - const sp& /* buffer */) { - VDS_LOGE("attachBuffer is not available for VirtualDisplaySurface"); - return INVALID_OPERATION; +status_t VirtualDisplaySurface::attachBuffer(int*, const sp&) { + UNSUPPORTED(); } status_t VirtualDisplaySurface::queueBuffer(int pslot, @@ -475,14 +452,14 @@ status_t VirtualDisplaySurface::queueBuffer(int pslot, return mSource[SOURCE_SINK]->queueBuffer(pslot, input, output); } - VDS_LOGW_IF(mDbgState != DBG_STATE_GPU, "Unexpected queueBuffer(pslot=%d) in %s state", pslot, - dbgStateStr()); - mDbgState = DBG_STATE_GPU_DONE; + VDS_LOGW_IF(mDebugState != DebugState::Gpu, "Unexpected %s(pslot=%d) in %s state", __func__, + pslot, ftl::enum_string(mDebugState).c_str()); + mDebugState = DebugState::GpuDone; - VDS_LOGV("queueBuffer pslot=%d", pslot); + VDS_LOGV("%s pslot=%d", __func__, pslot); status_t result; - if (mCompositionType == COMPOSITION_MIXED) { + if (mCompositionType == CompositionType::Mixed) { // Queue the buffer back into the scratch pool QueueBufferOutput scratchQBO; int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, pslot); @@ -498,15 +475,15 @@ status_t VirtualDisplaySurface::queueBuffer(int pslot, if (result != NO_ERROR) return result; VDS_LOGW_IF(item.mSlot != sslot, - "queueBuffer: acquired sslot %d from SCRATCH after queueing sslot %d", - item.mSlot, sslot); + "%s: acquired sslot %d from SCRATCH after queueing sslot %d", __func__, + item.mSlot, sslot); mFbProducerSlot = mapSource2ProducerSlot(SOURCE_SCRATCH, item.mSlot); mFbFence = mSlots[item.mSlot].mFence; } else { - LOG_FATAL_IF(mCompositionType != COMPOSITION_GPU, - "Unexpected queueBuffer in state %s for compositionType %s", dbgStateStr(), - dbgCompositionTypeStr(mCompositionType)); + LOG_FATAL_IF(mCompositionType != CompositionType::Gpu, + "Unexpected %s in state %s for composition type %s", __func__, + ftl::enum_string(mDebugState).c_str(), toString(mCompositionType).c_str()); // Extract the GPU release fence for HWC to acquire int64_t timestamp; @@ -533,9 +510,9 @@ status_t VirtualDisplaySurface::cancelBuffer(int pslot, return mSource[SOURCE_SINK]->cancelBuffer(mapProducer2SourceSlot(SOURCE_SINK, pslot), fence); } - VDS_LOGW_IF(mDbgState != DBG_STATE_GPU, "Unexpected cancelBuffer(pslot=%d) in %s state", pslot, - dbgStateStr()); - VDS_LOGV("cancelBuffer pslot=%d", pslot); + VDS_LOGW_IF(mDebugState != DebugState::Gpu, "Unexpected %s(pslot=%d) in %s state", __func__, + pslot, ftl::enum_string(mDebugState).c_str()); + VDS_LOGV("%s pslot=%d", __func__, pslot); Source source = fbSourceForCompositionType(mCompositionType); return mSource[source]->cancelBuffer( mapProducer2SourceSlot(source, pslot), fence); @@ -573,8 +550,8 @@ status_t VirtualDisplaySurface::disconnect(int api, DisconnectMode mode) { return mSource[SOURCE_SINK]->disconnect(api, mode); } -status_t VirtualDisplaySurface::setSidebandStream(const sp& /*stream*/) { - return INVALID_OPERATION; +status_t VirtualDisplaySurface::setSidebandStream(const sp&) { + UNSUPPORTED(); } void VirtualDisplaySurface::allocateBuffers(uint32_t /* width */, @@ -586,40 +563,32 @@ status_t VirtualDisplaySurface::allowAllocation(bool /* allow */) { return INVALID_OPERATION; } -status_t VirtualDisplaySurface::setGenerationNumber(uint32_t /* generation */) { - ALOGE("setGenerationNumber not supported on VirtualDisplaySurface"); - return INVALID_OPERATION; +status_t VirtualDisplaySurface::setGenerationNumber(uint32_t) { + UNSUPPORTED(); } String8 VirtualDisplaySurface::getConsumerName() const { return String8("VirtualDisplaySurface"); } -status_t VirtualDisplaySurface::setSharedBufferMode(bool /*sharedBufferMode*/) { - ALOGE("setSharedBufferMode not supported on VirtualDisplaySurface"); - return INVALID_OPERATION; +status_t VirtualDisplaySurface::setSharedBufferMode(bool) { + UNSUPPORTED(); } -status_t VirtualDisplaySurface::setAutoRefresh(bool /*autoRefresh*/) { - ALOGE("setAutoRefresh not supported on VirtualDisplaySurface"); - return INVALID_OPERATION; +status_t VirtualDisplaySurface::setAutoRefresh(bool) { + UNSUPPORTED(); } -status_t VirtualDisplaySurface::setDequeueTimeout(nsecs_t /* timeout */) { - ALOGE("setDequeueTimeout not supported on VirtualDisplaySurface"); - return INVALID_OPERATION; +status_t VirtualDisplaySurface::setDequeueTimeout(nsecs_t) { + UNSUPPORTED(); } -status_t VirtualDisplaySurface::getLastQueuedBuffer( - sp* /*outBuffer*/, sp* /*outFence*/, - float[16] /* outTransformMatrix*/) { - ALOGE("getLastQueuedBuffer not supported on VirtualDisplaySurface"); - return INVALID_OPERATION; +status_t VirtualDisplaySurface::getLastQueuedBuffer(sp*, sp*, float[16]) { + UNSUPPORTED(); } -status_t VirtualDisplaySurface::getUniqueId(uint64_t* /*outId*/) const { - ALOGE("getUniqueId not supported on VirtualDisplaySurface"); - return INVALID_OPERATION; +status_t VirtualDisplaySurface::getUniqueId(uint64_t*) const { + UNSUPPORTED(); } status_t VirtualDisplaySurface::getConsumerUsage(uint64_t* outUsage) const { @@ -633,7 +602,7 @@ void VirtualDisplaySurface::updateQueueBufferOutput( } void VirtualDisplaySurface::resetPerFrameState() { - mCompositionType = COMPOSITION_UNKNOWN; + mCompositionType = CompositionType::Unknown; mFbFence = Fence::NO_FENCE; mOutputFence = Fence::NO_FENCE; mOutputProducerSlot = -1; @@ -682,39 +651,16 @@ int VirtualDisplaySurface::mapProducer2SourceSlot(Source source, int pslot) { return mapSource2ProducerSlot(source, pslot); } -VirtualDisplaySurface::Source -VirtualDisplaySurface::fbSourceForCompositionType(CompositionType type) { - return type == COMPOSITION_MIXED ? SOURCE_SCRATCH : SOURCE_SINK; +auto VirtualDisplaySurface::fbSourceForCompositionType(CompositionType type) -> Source { + return type == CompositionType::Mixed ? SOURCE_SCRATCH : SOURCE_SINK; } -const char* VirtualDisplaySurface::dbgStateStr() const { - switch (mDbgState) { - case DBG_STATE_IDLE: - return "IDLE"; - case DBG_STATE_PREPARED: - return "PREPARED"; - case DBG_STATE_GPU: - return "GPU"; - case DBG_STATE_GPU_DONE: - return "GPU_DONE"; - case DBG_STATE_HWC: - return "HWC"; - default: - return "INVALID"; - } -} - -const char* VirtualDisplaySurface::dbgSourceStr(Source s) { - switch (s) { - case SOURCE_SINK: return "SINK"; - case SOURCE_SCRATCH: return "SCRATCH"; - default: return "INVALID"; - } +std::string VirtualDisplaySurface::toString(CompositionType type) { + using namespace std::literals; + return type == CompositionType::Unknown ? "Unknown"s : Flags(type).string(); } -// --------------------------------------------------------------------------- } // namespace android -// --------------------------------------------------------------------------- // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index bbb6306920..77207134b9 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H -#define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H +#pragma once #include #include @@ -28,9 +27,7 @@ #include "DisplayIdentification.h" -// --------------------------------------------------------------------------- namespace android { -// --------------------------------------------------------------------------- class HWComposer; class IProducerListener; @@ -94,7 +91,13 @@ public: virtual const sp& getClientTargetAcquireFence() const override; private: - enum Source {SOURCE_SINK = 0, SOURCE_SCRATCH = 1}; + enum Source : size_t { + SOURCE_SINK = 0, + SOURCE_SCRATCH = 1, + + ftl_first = SOURCE_SINK, + ftl_last = SOURCE_SCRATCH, + }; virtual ~VirtualDisplaySurface(); @@ -133,6 +136,8 @@ private: // Utility methods // static Source fbSourceForCompositionType(CompositionType); + static std::string toString(CompositionType); + status_t dequeueBuffer(Source, PixelFormat, uint64_t usage, int* sslot, sp*); void updateQueueBufferOutput(QueueBufferOutput&&); void resetPerFrameState(); @@ -197,7 +202,7 @@ private: // Composition type and graphics buffer source for the current frame. // Valid after prepareFrame(), cleared in onFrameCommitted. - CompositionType mCompositionType; + CompositionType mCompositionType = CompositionType::Unknown; // mFbFence is the fence HWC should wait for before reading the framebuffer // target buffer. @@ -219,47 +224,42 @@ private: // +-----------+-------------------+-------------+ // | State | Event || Next State | // +-----------+-------------------+-------------+ - // | IDLE | beginFrame || BEGUN | - // | BEGUN | prepareFrame || PREPARED | - // | PREPARED | dequeueBuffer [1] || GPU | - // | PREPARED | advanceFrame [2] || HWC | - // | GPU | queueBuffer || GPU_DONE | - // | GPU_DONE | advanceFrame || HWC | - // | HWC | onFrameCommitted || IDLE | + // | Idle | beginFrame || Begun | + // | Begun | prepareFrame || Prepared | + // | Prepared | dequeueBuffer [1] || Gpu | + // | Prepared | advanceFrame [2] || Hwc | + // | Gpu | queueBuffer || GpuDone | + // | GpuDone | advanceFrame || Hwc | + // | Hwc | onFrameCommitted || Idle | // +-----------+-------------------++------------+ - // [1] COMPOSITION_GPU and COMPOSITION_MIXED frames. - // [2] COMPOSITION_HWC frames. + // [1] CompositionType::Gpu and CompositionType::Mixed frames. + // [2] CompositionType::Hwc frames. // - enum DbgState { + enum class DebugState { // no buffer dequeued, don't know anything about the next frame - DBG_STATE_IDLE, + Idle, // output buffer dequeued, framebuffer source not yet known - DBG_STATE_BEGUN, + Begun, // output buffer dequeued, framebuffer source known but not provided // to GPU yet. - DBG_STATE_PREPARED, + Prepared, // GPU driver has a buffer dequeued - DBG_STATE_GPU, + Gpu, // GPU driver has queued the buffer, we haven't sent it to HWC yet - DBG_STATE_GPU_DONE, + GpuDone, // HWC has the buffer for this frame - DBG_STATE_HWC, - }; - DbgState mDbgState; - CompositionType mDbgLastCompositionType; + Hwc, - const char* dbgStateStr() const; - static const char* dbgSourceStr(Source s); + ftl_last = Hwc + }; + DebugState mDebugState = DebugState::Idle; + CompositionType mDebugLastCompositionType = CompositionType::Unknown; - bool mMustRecompose; + bool mMustRecompose = false; compositionengine::impl::HwcBufferCache mHwcBufferCache; bool mForceHwcCopy; }; -// --------------------------------------------------------------------------- } // namespace android -// --------------------------------------------------------------------------- - -#endif // ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index c294ff2695..0c4e1120fc 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -304,7 +304,7 @@ SurfaceFrame::SurfaceFrame(const FrameTimelineInfo& frameTimelineInfo, pid_t own frametimeline::TimelineItem&& predictions, std::shared_ptr timeStats, JankClassificationThresholds thresholds, - TraceCookieCounter* traceCookieCounter, bool isBuffer, int32_t gameMode) + TraceCookieCounter* traceCookieCounter, bool isBuffer, GameMode gameMode) : mToken(frameTimelineInfo.vsyncId), mInputEventId(frameTimelineInfo.inputEventId), mOwnerPid(ownerPid), @@ -778,7 +778,7 @@ void FrameTimeline::registerDataSource() { std::shared_ptr FrameTimeline::createSurfaceFrameForToken( const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, int32_t layerId, - std::string layerName, std::string debugName, bool isBuffer, int32_t gameMode) { + std::string layerName, std::string debugName, bool isBuffer, GameMode gameMode) { ATRACE_CALL(); if (frameTimelineInfo.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) { return std::make_shared(frameTimelineInfo, ownerPid, ownerUid, layerId, diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h index d08344ef6e..36d629077d 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -161,7 +162,7 @@ public: int32_t layerId, std::string layerName, std::string debugName, PredictionState predictionState, TimelineItem&& predictions, std::shared_ptr timeStats, JankClassificationThresholds thresholds, - TraceCookieCounter* traceCookieCounter, bool isBuffer, int32_t gameMode); + TraceCookieCounter* traceCookieCounter, bool isBuffer, GameMode); ~SurfaceFrame() = default; // Returns std::nullopt if the frame hasn't been classified yet. @@ -267,7 +268,7 @@ private: // buffer(animations) bool mIsBuffer; // GameMode from the layer. Used in metrics. - int32_t mGameMode = 0; + GameMode mGameMode = GameMode::Unsupported; }; /* @@ -288,7 +289,7 @@ public: virtual std::shared_ptr createSurfaceFrameForToken( const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, int32_t layerId, std::string layerName, std::string debugName, bool isBuffer, - int32_t gameMode) = 0; + GameMode) = 0; // Adds a new SurfaceFrame to the current DisplayFrame. Frames from multiple layers can be // composited into one display frame. @@ -448,7 +449,7 @@ public: std::shared_ptr createSurfaceFrameForToken( const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, int32_t layerId, std::string layerName, std::string debugName, bool isBuffer, - int32_t gameMode) override; + GameMode) override; void addSurfaceFrame(std::shared_ptr surfaceFrame) override; void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) override; void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr& presentFence, diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 968a49d526..67f9a92385 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -1411,19 +1412,6 @@ void Layer::miniDumpHeader(std::string& result) { result.append("\n"); } -std::string Layer::frameRateCompatibilityString(Layer::FrameRateCompatibility compatibility) { - switch (compatibility) { - case FrameRateCompatibility::Default: - return "Default"; - case FrameRateCompatibility::ExactOrMultiple: - return "ExactOrMultiple"; - case FrameRateCompatibility::NoVote: - return "NoVote"; - case FrameRateCompatibility::Exact: - return "Exact"; - } -} - void Layer::miniDump(std::string& result, const DisplayDevice& display) const { const auto outputLayer = findOutputLayerForDisplay(&display); if (!outputLayer) { @@ -1462,8 +1450,8 @@ void Layer::miniDump(std::string& result, const DisplayDevice& display) const { const auto frameRate = getFrameRateForLayerTree(); if (frameRate.rate.isValid() || frameRate.type != FrameRateCompatibility::Default) { StringAppendF(&result, "%s %15s %17s", to_string(frameRate.rate).c_str(), - frameRateCompatibilityString(frameRate.type).c_str(), - toString(frameRate.seamlessness).c_str()); + ftl::enum_string(frameRate.type).c_str(), + ftl::enum_string(frameRate.seamlessness).c_str()); } else { result.append(41, ' '); } @@ -1546,11 +1534,10 @@ size_t Layer::getChildrenCount() const { return count; } -void Layer::setGameModeForTree(int parentGameMode) { - int gameMode = parentGameMode; - auto& currentState = getDrawingState(); +void Layer::setGameModeForTree(GameMode gameMode) { + const auto& currentState = getDrawingState(); if (currentState.metadata.has(METADATA_GAME_MODE)) { - gameMode = currentState.metadata.getInt32(METADATA_GAME_MODE, 0); + gameMode = static_cast(currentState.metadata.getInt32(METADATA_GAME_MODE, 0)); } setGameMode(gameMode); for (const sp& child : mCurrentChildren) { @@ -1576,7 +1563,7 @@ ssize_t Layer::removeChild(const sp& layer) { const auto removeResult = mCurrentChildren.remove(layer); updateTreeHasFrameRateVote(); - layer->setGameModeForTree(0); + layer->setGameModeForTree(GameMode::Unsupported); layer->updateTreeHasFrameRateVote(); return removeResult; @@ -2631,12 +2618,11 @@ bool Layer::setDropInputMode(gui::DropInputMode mode) { // --------------------------------------------------------------------------- std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) { - return stream << "{rate=" << rate.rate - << " type=" << Layer::frameRateCompatibilityString(rate.type) - << " seamlessness=" << toString(rate.seamlessness) << "}"; + return stream << "{rate=" << rate.rate << " type=" << ftl::enum_string(rate.type) + << " seamlessness=" << ftl::enum_string(rate.seamlessness) << '}'; } -}; // namespace android +} // namespace android #if defined(__gl_h_) #error "don't include gl/gl.h in this file" diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 041b439ac7..47885a4f0c 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -328,7 +328,6 @@ public: static bool isLayerFocusedBasedOnPriority(int32_t priority); static void miniDumpHeader(std::string& result); - static std::string frameRateCompatibilityString(FrameRateCompatibility compatibility); // Provide unique string for each class type in the Layer hierarchy virtual const char* getType() const = 0; @@ -854,12 +853,12 @@ public: */ bool hasInputInfo() const; - // Sets the parent's gameMode for this layer and all its children. Parent's gameMode is applied - // only to layers that do not have the GAME_MODE_METADATA set by WMShell. Any layer(along with - // its children) that has the metadata set will use the gameMode from the metadata. - void setGameModeForTree(int32_t parentGameMode); - void setGameMode(int32_t gameMode) { mGameMode = gameMode; }; - int32_t getGameMode() const { return mGameMode; } + // Sets the GameMode for the tree rooted at this layer. A layer in the tree inherits this + // GameMode unless it (or an ancestor) has GAME_MODE_METADATA. + void setGameModeForTree(GameMode); + + void setGameMode(GameMode gameMode) { mGameMode = gameMode; } + GameMode getGameMode() const { return mGameMode; } virtual uid_t getOwnerUid() const { return mOwnerUid; } @@ -1110,9 +1109,8 @@ private: // shadow radius is the set shadow radius, otherwise its the parent's shadow radius. float mEffectiveShadowRadius = 0.f; - // Game mode for the layer. Set by WindowManagerShell, game mode is used in - // metrics(SurfaceFlingerStats). - int32_t mGameMode = 0; + // Game mode for the layer. Set by WindowManagerShell and recorded by SurfaceFlingerStats. + GameMode mGameMode = GameMode::Unsupported; // A list of regions on this layer that should have blurs. const std::vector getBlurRegions() const; diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index 314526a99d..ae61eeb660 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -28,6 +28,7 @@ #include #include +#include #undef LOG_TAG #define LOG_TAG "LayerInfo" @@ -257,10 +258,10 @@ LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateConfigs& ref return {LayerHistory::LayerVoteType::Max, Fps()}; } -const char* LayerInfo::getTraceTag(android::scheduler::LayerHistory::LayerVoteType type) const { +const char* LayerInfo::getTraceTag(LayerHistory::LayerVoteType type) const { if (mTraceTags.count(type) == 0) { - const auto tag = "LFPS " + mName + " " + RefreshRateConfigs::layerVoteTypeString(type); - mTraceTags.emplace(type, tag); + auto tag = "LFPS " + mName + " " + ftl::enum_string(type); + mTraceTags.emplace(type, std::move(tag)); } return mTraceTags.at(type).c_str(); diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index 18ed95ec0f..690abda613 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -82,6 +82,8 @@ public: NoVote, // Layer doesn't have any requirements for the refresh rate and // should not be considered when the display refresh rate is determined. + + ftl_last = NoVote }; // Encapsulates the frame rate and compatibility of the layer. This information will be used diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 0d17b0ca94..71d563130e 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -21,23 +21,27 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wextra" -#include "RefreshRateConfigs.h" +#include +#include + #include #include +#include #include -#include -#include + #include "../SurfaceFlingerProperties.h" +#include "RefreshRateConfigs.h" #undef LOG_TAG #define LOG_TAG "RefreshRateConfigs" namespace android::scheduler { namespace { + std::string formatLayerInfo(const RefreshRateConfigs::LayerRequirement& layer, float weight) { return base::StringPrintf("%s (type=%s, weight=%.2f seamlessness=%s) %s", layer.name.c_str(), - RefreshRateConfigs::layerVoteTypeString(layer.vote).c_str(), weight, - toString(layer.seamlessness).c_str(), + ftl::enum_string(layer.vote).c_str(), weight, + ftl::enum_string(layer.seamlessness).c_str(), to_string(layer.desiredRefreshRate).c_str()); } @@ -74,25 +78,6 @@ std::string RefreshRate::toString() const { mode->getWidth(), mode->getHeight(), getModeGroup()); } -std::string RefreshRateConfigs::layerVoteTypeString(LayerVoteType vote) { - switch (vote) { - case LayerVoteType::NoVote: - return "NoVote"; - case LayerVoteType::Min: - return "Min"; - case LayerVoteType::Max: - return "Max"; - case LayerVoteType::Heuristic: - return "Heuristic"; - case LayerVoteType::ExplicitDefault: - return "ExplicitDefault"; - case LayerVoteType::ExplicitExactOrMultiple: - return "ExplicitExactOrMultiple"; - case LayerVoteType::ExplicitExact: - return "ExplicitExact"; - } -} - std::string RefreshRateConfigs::Policy::toString() const { return base::StringPrintf("default mode ID: %d, allowGroupSwitching = %d" ", primary range: %s, app request range: %s", @@ -405,7 +390,7 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( for (const auto& layer : layers) { ALOGV("Calculating score for %s (%s, weight %.2f, desired %.2f) ", layer.name.c_str(), - layerVoteTypeString(layer.vote).c_str(), layer.weight, + ftl::enum_string(layer.vote).c_str(), layer.weight, layer.desiredRefreshRate.getValue()); if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min) { continue; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 8a1c2062a6..8c38083561 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -206,6 +206,7 @@ public: ExplicitExact, // Specific refresh rate that was provided by the app with // Exact compatibility + ftl_last = ExplicitExact }; // Captures the layer requirements for a refresh rate. This will be used to determine the @@ -285,9 +286,6 @@ public: // Stores the current modeId the device operates at void setCurrentModeId(DisplayModeId) EXCLUDES(mLock); - // Returns a string that represents the layer vote type - static std::string layerVoteTypeString(LayerVoteType vote); - // Returns a known frame rate that is the closest to frameRate Fps findClosestKnownFrameRate(Fps frameRate) const; diff --git a/services/surfaceflinger/Scheduler/Timer.cpp b/services/surfaceflinger/Scheduler/Timer.cpp index c9c2d84a2a..22c3a709de 100644 --- a/services/surfaceflinger/Scheduler/Timer.cpp +++ b/services/surfaceflinger/Scheduler/Timer.cpp @@ -17,14 +17,18 @@ #undef LOG_TAG #define LOG_TAG "SchedulerTimer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include -#include + +#include +#include + #include #include #include + +#include +#include +#include #include -#include -#include #include "SchedulerUtils.h" #include "Timer.h" @@ -215,26 +219,9 @@ void Timer::setDebugState(DebugState state) { mDebugState = state; } -const char* Timer::strDebugState(DebugState state) const { - switch (state) { - case DebugState::Reset: - return "Reset"; - case DebugState::Running: - return "Running"; - case DebugState::Waiting: - return "Waiting"; - case DebugState::Reading: - return "Reading"; - case DebugState::InCallback: - return "InCallback"; - case DebugState::Terminated: - return "Terminated"; - } -} - void Timer::dump(std::string& result) const { std::lock_guard lock(mMutex); - StringAppendF(&result, "\t\tDebugState: %s\n", strDebugState(mDebugState)); + StringAppendF(&result, "\t\tDebugState: %s\n", ftl::enum_string(mDebugState).c_str()); } } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/Timer.h b/services/surfaceflinger/Scheduler/Timer.h index 69ce079437..628d800bc7 100644 --- a/services/surfaceflinger/Scheduler/Timer.h +++ b/services/surfaceflinger/Scheduler/Timer.h @@ -37,11 +37,20 @@ public: void dump(std::string& result) const final; private: - enum class DebugState { Reset, Running, Waiting, Reading, InCallback, Terminated }; + enum class DebugState { + Reset, + Running, + Waiting, + Reading, + InCallback, + Terminated, + + ftl_last = Terminated + }; + void reset(); void cleanup(); void setDebugState(DebugState state) EXCLUDES(mMutex); - const char* strDebugState(DebugState state) const; int mTimerFd = -1; int mEpollFd = -1; diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Seamlessness.h b/services/surfaceflinger/Scheduler/include/scheduler/Seamlessness.h index d7667ec9c6..93bf726731 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/Seamlessness.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/Seamlessness.h @@ -17,7 +17,8 @@ #pragma once #include -#include + +#include namespace android::scheduler { @@ -30,23 +31,14 @@ enum class Seamlessness { // Indicates no preference for seamlessness. For such layers the system will // prefer seamless switches, but also non-seamless switches to the group of the // default config are allowed. - Default -}; + Default, -inline std::string toString(Seamlessness seamlessness) { - switch (seamlessness) { - case Seamlessness::OnlySeamless: - return "OnlySeamless"; - case Seamlessness::SeamedAndSeamless: - return "SeamedAndSeamless"; - case Seamlessness::Default: - return "Default"; - } -} + ftl_last = Default +}; // Used by gtest -inline std::ostream& operator<<(std::ostream& os, Seamlessness val) { - return os << toString(val); +inline std::ostream& operator<<(std::ostream& os, Seamlessness s) { + return os << ftl::enum_string(s); } } // namespace android::scheduler diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e497d95306..0a6eb4ff2a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4158,13 +4158,14 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime std::optional dequeueBufferTimestamp; if (what & layer_state_t::eMetadataChanged) { dequeueBufferTimestamp = s.metadata.getInt64(METADATA_DEQUEUE_TIME); - auto gameMode = s.metadata.getInt32(METADATA_GAME_MODE, -1); - if (gameMode != -1) { + + if (const int32_t gameMode = s.metadata.getInt32(METADATA_GAME_MODE, -1); gameMode != -1) { // The transaction will be received on the Task layer and needs to be applied to all // child layers. Child layers that are added at a later point will obtain the game mode // info through addChild(). - layer->setGameModeForTree(gameMode); + layer->setGameModeForTree(static_cast(gameMode)); } + if (layer->setMetadata(s.metadata)) flags |= eTraversalNeeded; } if (what & layer_state_t::eColorSpaceAgnosticChanged) { diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index bf2038b277..b1a2bdaa91 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #undef LOG_TAG #define LOG_TAG "TimeStats" #define ATRACE_TAG ATRACE_TAG_GRAPHICS @@ -28,6 +27,7 @@ #include #include +#include #include "TimeStats.h" #include "timestatsproto/TimeStatsHelper.h" @@ -58,15 +58,15 @@ FrameTimingHistogram histogramToProto(const std::unordered_map return histogramProto; } -SurfaceflingerStatsLayerInfo_GameMode gameModeToProto(int32_t gameMode) { +SurfaceflingerStatsLayerInfo_GameMode gameModeToProto(GameMode gameMode) { switch (gameMode) { - case TimeStatsHelper::GameModeUnsupported: + case GameMode::Unsupported: return SurfaceflingerStatsLayerInfo::GAME_MODE_UNSUPPORTED; - case TimeStatsHelper::GameModeStandard: + case GameMode::Standard: return SurfaceflingerStatsLayerInfo::GAME_MODE_STANDARD; - case TimeStatsHelper::GameModePerformance: + case GameMode::Performance: return SurfaceflingerStatsLayerInfo::GAME_MODE_PERFORMANCE; - case TimeStatsHelper::GameModeBattery: + case GameMode::Battery: return SurfaceflingerStatsLayerInfo::GAME_MODE_BATTERY; default: return SurfaceflingerStatsLayerInfo::GAME_MODE_UNSPECIFIED; @@ -454,7 +454,7 @@ static int32_t clampToNearestBucket(Fps fps, size_t bucketWidth) { void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate, std::optional renderRate, SetFrameRateVote frameRateVote, - int32_t gameMode) { + GameMode gameMode) { ATRACE_CALL(); ALOGV("[%d]-flushAvailableRecordsToStatsLocked", layerId); @@ -554,7 +554,7 @@ static bool layerNameIsValid(const std::string& layerName) { } bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName, - int32_t gameMode) { + GameMode gameMode) { uint32_t layerRecords = 0; for (const auto& record : mTimeStats.stats) { if (record.second.stats.count({uid, layerName, gameMode}) > 0) { @@ -568,7 +568,7 @@ bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName } void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName, - uid_t uid, nsecs_t postTime, int32_t gameMode) { + uid_t uid, nsecs_t postTime, GameMode gameMode) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -718,7 +718,7 @@ void TimeStats::setAcquireFence(int32_t layerId, uint64_t frameNumber, void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime, Fps displayRefreshRate, std::optional renderRate, - SetFrameRateVote frameRateVote, int32_t gameMode) { + SetFrameRateVote frameRateVote, GameMode gameMode) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -744,7 +744,7 @@ void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t pr void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber, const std::shared_ptr& presentFence, Fps displayRefreshRate, std::optional renderRate, - SetFrameRateVote frameRateVote, int32_t gameMode) { + SetFrameRateVote frameRateVote, GameMode gameMode) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -823,7 +823,7 @@ void TimeStats::incrementJankyFrames(const JankyFramesInfo& info) { // the first jank record is not dropped. static const std::string kDefaultLayerName = "none"; - static constexpr int32_t kDefaultGameMode = TimeStatsHelper::GameModeUnsupported; + constexpr GameMode kDefaultGameMode = GameMode::Unsupported; const int32_t refreshRateBucket = clampToNearestBucket(info.refreshRate, REFRESH_RATE_BUCKET_WIDTH); diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index 23f19b5cfd..77c7973532 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -79,7 +80,7 @@ public: const std::shared_ptr& readyFence) = 0; virtual void setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName, - uid_t uid, nsecs_t postTime, int32_t gameMode) = 0; + uid_t uid, nsecs_t postTime, GameMode) = 0; virtual void setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) = 0; // Reasons why latching a particular buffer may be skipped enum class LatchSkipReason { @@ -101,11 +102,11 @@ public: // rendering path, as they flush prior fences if those fences have fired. virtual void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime, Fps displayRefreshRate, std::optional renderRate, - SetFrameRateVote frameRateVote, int32_t gameMode) = 0; + SetFrameRateVote frameRateVote, GameMode) = 0; virtual void setPresentFence(int32_t layerId, uint64_t frameNumber, const std::shared_ptr& presentFence, Fps displayRefreshRate, std::optional renderRate, - SetFrameRateVote frameRateVote, int32_t gameMode) = 0; + SetFrameRateVote frameRateVote, GameMode) = 0; // Increments janky frames, blamed to the provided {refreshRate, renderRate, uid, layerName} // key, with JankMetadata as supplementary reasons for the jank. Because FrameTimeline is the @@ -123,7 +124,7 @@ public: std::optional renderRate; uid_t uid = 0; std::string layerName; - int32_t gameMode = 0; + GameMode gameMode = GameMode::Unsupported; int32_t reasons = 0; nsecs_t displayDeadlineDelta = 0; nsecs_t displayPresentJitter = 0; @@ -194,7 +195,7 @@ class TimeStats : public android::TimeStats { struct LayerRecord { uid_t uid; std::string layerName; - int32_t gameMode = 0; + GameMode gameMode = GameMode::Unsupported; // This is the index in timeRecords, at which the timestamps for that // specific frame are still not fully received. This is not waiting for // fences to signal, but rather waiting to receive those fences/timestamps. @@ -247,7 +248,7 @@ public: const std::shared_ptr& readyFence) override; void setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName, uid_t uid, - nsecs_t postTime, int32_t gameMode) override; + nsecs_t postTime, GameMode) override; void setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) override; void incrementLatchSkipped(int32_t layerId, LatchSkipReason reason) override; void incrementBadDesiredPresent(int32_t layerId) override; @@ -256,12 +257,11 @@ public: void setAcquireFence(int32_t layerId, uint64_t frameNumber, const std::shared_ptr& acquireFence) override; void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime, - Fps displayRefreshRate, std::optional renderRate, - SetFrameRateVote frameRateVote, int32_t gameMode) override; + Fps displayRefreshRate, std::optional renderRate, SetFrameRateVote, + GameMode) override; void setPresentFence(int32_t layerId, uint64_t frameNumber, const std::shared_ptr& presentFence, Fps displayRefreshRate, - std::optional renderRate, SetFrameRateVote frameRateVote, - int32_t gameMode) override; + std::optional renderRate, SetFrameRateVote, GameMode) override; void incrementJankyFrames(const JankyFramesInfo& info) override; // Clean up the layer record @@ -282,11 +282,11 @@ private: bool populateLayerAtom(std::string* pulledData); bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord); void flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate, - std::optional renderRate, - SetFrameRateVote frameRateVote, int32_t gameMode); + std::optional renderRate, SetFrameRateVote, + GameMode); void flushPowerTimeLocked(); void flushAvailableGlobalRecordsToStatsLocked(); - bool canAddNewAggregatedStats(uid_t uid, const std::string& layerName, int32_t gameMode); + bool canAddNewAggregatedStats(uid_t uid, const std::string& layerName, GameMode); void enable(); void disable(); diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp index ffb2f0921d..69afa2a7a1 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp +++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp @@ -16,9 +16,10 @@ #include "timestatsproto/TimeStatsHelper.h" #include -#include +#include #include +#include #define HISTOGRAM_SIZE 85 @@ -91,51 +92,15 @@ std::string TimeStatsHelper::JankPayload::toString() const { return result; } -std::string TimeStatsHelper::SetFrameRateVote::toString(FrameRateCompatibility compatibility) { - switch (compatibility) { - case FrameRateCompatibility::Undefined: - return "Undefined"; - case FrameRateCompatibility::Default: - return "Default"; - case FrameRateCompatibility::ExactOrMultiple: - return "ExactOrMultiple"; - } -} - -std::string TimeStatsHelper::SetFrameRateVote::toString(Seamlessness seamlessness) { - switch (seamlessness) { - case Seamlessness::Undefined: - return "Undefined"; - case Seamlessness::ShouldBeSeamless: - return "ShouldBeSeamless"; - case Seamlessness::NotRequired: - return "NotRequired"; - } -} - std::string TimeStatsHelper::SetFrameRateVote::toString() const { std::string result; StringAppendF(&result, "frameRate = %.2f\n", frameRate); StringAppendF(&result, "frameRateCompatibility = %s\n", - toString(frameRateCompatibility).c_str()); - StringAppendF(&result, "seamlessness = %s\n", toString(seamlessness).c_str()); + ftl::enum_string(frameRateCompatibility).c_str()); + StringAppendF(&result, "seamlessness = %s\n", ftl::enum_string(seamlessness).c_str()); return result; } -std::string TimeStatsHelper::TimeStatsLayer::toString(int32_t gameMode) const { - switch (gameMode) { - case TimeStatsHelper::GameModeUnsupported: - return "GameModeUnsupported"; - case TimeStatsHelper::GameModeStandard: - return "GameModeStandard"; - case TimeStatsHelper::GameModePerformance: - return "GameModePerformance"; - case TimeStatsHelper::GameModeBattery: - return "GameModeBattery"; - default: - return "GameModeUnspecified"; - } -} std::string TimeStatsHelper::TimeStatsLayer::toString() const { std::string result = "\n"; StringAppendF(&result, "displayRefreshRate = %d fps\n", displayRefreshRateBucket); @@ -143,7 +108,7 @@ std::string TimeStatsHelper::TimeStatsLayer::toString() const { StringAppendF(&result, "uid = %d\n", uid); StringAppendF(&result, "layerName = %s\n", layerName.c_str()); StringAppendF(&result, "packageName = %s\n", packageName.c_str()); - StringAppendF(&result, "gameMode = %s\n", toString(gameMode).c_str()); + StringAppendF(&result, "gameMode = %s\n", ftl::enum_string(gameMode).c_str()); StringAppendF(&result, "totalFrames = %d\n", totalFrames); StringAppendF(&result, "droppedFrames = %d\n", droppedFrames); StringAppendF(&result, "lateAcquireFrames = %d\n", lateAcquireFrames); diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h index 2afff8d313..438561cc05 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h +++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h @@ -15,6 +15,7 @@ */ #pragma once +#include #include #include @@ -63,6 +64,8 @@ public: Undefined = 0, Default = 1, ExactOrMultiple = 2, + + ftl_last = ExactOrMultiple } frameRateCompatibility = FrameRateCompatibility::Undefined; // Needs to be in sync with atoms.proto @@ -70,25 +73,13 @@ public: Undefined = 0, ShouldBeSeamless = 1, NotRequired = 2, + + ftl_last = NotRequired } seamlessness = Seamlessness::Undefined; - static std::string toString(FrameRateCompatibility); - static std::string toString(Seamlessness); std::string toString() const; }; - /** - * GameMode of the layer. GameModes are set by SysUI through WMShell. - * Actual game mode definitions are managed by GameManager.java - * The values defined here should always be in sync with the ones in GameManager. - */ - enum GameMode { - GameModeUnsupported = 0, - GameModeStandard = 1, - GameModePerformance = 2, - GameModeBattery = 3, - }; - class TimeStatsLayer { public: uid_t uid; @@ -96,7 +87,7 @@ public: std::string packageName; int32_t displayRefreshRateBucket = 0; int32_t renderRateBucket = 0; - int32_t gameMode = 0; + GameMode gameMode = GameMode::Unsupported; int32_t totalFrames = 0; int32_t droppedFrames = 0; int32_t lateAcquireFrames = 0; @@ -106,7 +97,6 @@ public: std::unordered_map deltas; std::string toString() const; - std::string toString(int32_t gameMode) const; SFTimeStatsLayerProto toProto() const; }; @@ -137,13 +127,14 @@ public: struct LayerStatsKey { uid_t uid = 0; std::string layerName; - int32_t gameMode = 0; + GameMode gameMode = GameMode::Unsupported; struct Hasher { size_t operator()(const LayerStatsKey& key) const { size_t uidHash = std::hash{}(key.uid); size_t layerNameHash = std::hash{}(key.layerName); - size_t gameModeHash = std::hash{}(key.gameMode); + using T = std::underlying_type_t; + size_t gameModeHash = std::hash{}(static_cast(key.gameMode)); return HashCombine(uidHash, HashCombine(layerNameHash, gameModeHash)); } }; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 8d2c078305..c7c6b06386 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -370,7 +370,7 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1); EXPECT_CALL(*test->mDisplaySurface, - prepareFrame(compositionengine::DisplaySurface::COMPOSITION_HWC)) + prepareFrame(compositionengine::DisplaySurface::CompositionType::Hwc)) .Times(1); } @@ -384,7 +384,7 @@ struct BaseDisplayVariant { static void setupRECompositionCallExpectations(CompositionTest* test) { EXPECT_CALL(*test->mDisplaySurface, - prepareFrame(compositionengine::DisplaySurface::COMPOSITION_GPU)) + prepareFrame(compositionengine::DisplaySurface::CompositionType::Gpu)) .Times(1); EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence()) .WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence)); diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp index 9fbaeced7b..397c6193bf 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -169,13 +169,14 @@ public: static const std::string sLayerNameOne = "layer1"; static const std::string sLayerNameTwo = "layer2"; -static constexpr const uid_t sUidOne = 0; -static constexpr pid_t sPidOne = 10; -static constexpr pid_t sPidTwo = 20; -static constexpr int32_t sInputEventId = 5; -static constexpr int32_t sLayerIdOne = 1; -static constexpr int32_t sLayerIdTwo = 2; -static constexpr int32_t sGameMode = 0; + +constexpr const uid_t sUidOne = 0; +constexpr pid_t sPidOne = 10; +constexpr pid_t sPidTwo = 20; +constexpr int32_t sInputEventId = 5; +constexpr int32_t sLayerIdOne = 1; +constexpr int32_t sLayerIdTwo = 2; +constexpr GameMode sGameMode = GameMode::Unsupported; TEST_F(FrameTimelineTest, tokenManagerRemovesStalePredictions) { int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0}); diff --git a/services/surfaceflinger/tests/unittests/GameModeTest.cpp b/services/surfaceflinger/tests/unittests/GameModeTest.cpp index d6459429fb..981ca1d227 100644 --- a/services/surfaceflinger/tests/unittests/GameModeTest.cpp +++ b/services/surfaceflinger/tests/unittests/GameModeTest.cpp @@ -91,8 +91,8 @@ public: } // Mocks the behavior of applying a transaction from WMShell - void setGameModeMetadata(sp layer, int gameMode) { - mLayerMetadata.setInt32(METADATA_GAME_MODE, gameMode); + void setGameModeMetadata(sp layer, GameMode gameMode) { + mLayerMetadata.setInt32(METADATA_GAME_MODE, static_cast(gameMode)); layer->setMetadata(mLayerMetadata); layer->setGameModeForTree(gameMode); } @@ -109,51 +109,52 @@ TEST_F(GameModeTest, SetGameModeSetsForAllCurrentChildren) { sp childLayer2 = createBufferStateLayer(); rootLayer->addChild(childLayer1); rootLayer->addChild(childLayer2); - rootLayer->setGameModeForTree(/*gameMode*/ 2); + rootLayer->setGameModeForTree(GameMode::Performance); - EXPECT_EQ(rootLayer->getGameMode(), 2); - EXPECT_EQ(childLayer1->getGameMode(), 2); - EXPECT_EQ(childLayer2->getGameMode(), 2); + EXPECT_EQ(rootLayer->getGameMode(), GameMode::Performance); + EXPECT_EQ(childLayer1->getGameMode(), GameMode::Performance); + EXPECT_EQ(childLayer2->getGameMode(), GameMode::Performance); } TEST_F(GameModeTest, AddChildAppliesGameModeFromParent) { sp rootLayer = createBufferStateLayer(); sp childLayer = createBufferStateLayer(); - rootLayer->setGameModeForTree(/*gameMode*/ 2); + rootLayer->setGameModeForTree(GameMode::Performance); rootLayer->addChild(childLayer); - EXPECT_EQ(rootLayer->getGameMode(), 2); - EXPECT_EQ(childLayer->getGameMode(), 2); + EXPECT_EQ(rootLayer->getGameMode(), GameMode::Performance); + EXPECT_EQ(childLayer->getGameMode(), GameMode::Performance); } TEST_F(GameModeTest, RemoveChildResetsGameMode) { sp rootLayer = createBufferStateLayer(); sp childLayer = createBufferStateLayer(); - rootLayer->setGameModeForTree(/*gameMode*/ 2); + rootLayer->setGameModeForTree(GameMode::Performance); rootLayer->addChild(childLayer); - EXPECT_EQ(rootLayer->getGameMode(), 2); - EXPECT_EQ(childLayer->getGameMode(), 2); + EXPECT_EQ(rootLayer->getGameMode(), GameMode::Performance); + EXPECT_EQ(childLayer->getGameMode(), GameMode::Performance); rootLayer->removeChild(childLayer); - EXPECT_EQ(childLayer->getGameMode(), 0); + EXPECT_EQ(childLayer->getGameMode(), GameMode::Unsupported); } TEST_F(GameModeTest, ReparentingDoesNotOverrideMetadata) { sp rootLayer = createBufferStateLayer(); sp childLayer1 = createBufferStateLayer(); sp childLayer2 = createBufferStateLayer(); - rootLayer->setGameModeForTree(/*gameMode*/ 1); + rootLayer->setGameModeForTree(GameMode::Standard); rootLayer->addChild(childLayer1); - setGameModeMetadata(childLayer2, /*gameMode*/ 2); + setGameModeMetadata(childLayer2, GameMode::Performance); rootLayer->addChild(childLayer2); - EXPECT_EQ(rootLayer->getGameMode(), 1); - EXPECT_EQ(childLayer1->getGameMode(), 1); - EXPECT_EQ(childLayer2->getGameMode(), 2); + EXPECT_EQ(rootLayer->getGameMode(), GameMode::Standard); + EXPECT_EQ(childLayer1->getGameMode(), GameMode::Standard); + EXPECT_EQ(childLayer2->getGameMode(), GameMode::Performance); rootLayer->removeChild(childLayer2); - EXPECT_EQ(childLayer2->getGameMode(), 2); + EXPECT_EQ(childLayer2->getGameMode(), GameMode::Performance); } -} // namespace android \ No newline at end of file + +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index fc84d48b46..98746bcd21 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -21,10 +21,9 @@ #undef LOG_TAG #define LOG_TAG "SchedulerUnittests" +#include #include #include -#include - #include #include "DisplayHardware/HWC2.h" @@ -1975,7 +1974,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_deviceWithCloseRefreshRates) { layers[0].vote = vote; EXPECT_EQ(fps.getIntValue(), refreshRateConfigs->getBestRefreshRate(layers, {}).getFps().getIntValue()) - << "Failed for " << RefreshRateConfigs::layerVoteTypeString(vote); + << "Failed for " << ftl::enum_string(vote); }; for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) { diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index 1487a962f9..0ef8456739 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -70,9 +70,9 @@ using SurfaceflingerStatsLayerInfoWrapper = #define NUM_LAYERS 1 #define NUM_LAYERS_INVALID "INVALID" -const constexpr Fps kRefreshRate0 = 61_Hz; -const constexpr Fps kRenderRate0 = 31_Hz; -static constexpr int32_t kGameMode = TimeStatsHelper::GameModeUnsupported; +constexpr Fps kRefreshRate0 = 61_Hz; +constexpr Fps kRenderRate0 = 31_Hz; +constexpr GameMode kGameMode = GameMode::Unsupported; enum InputCommand : int32_t { ENABLE = 0, @@ -145,14 +145,14 @@ public: std::string inputCommand(InputCommand cmd, bool useProto); void setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts, - TimeStats::SetFrameRateVote frameRateVote, int32_t gameMode); + TimeStats::SetFrameRateVote, GameMode); int32_t genRandomInt32(int32_t begin, int32_t end); template void insertTimeRecord(const TimeStamp (&sequence)[N], int32_t id, uint64_t frameNumber, nsecs_t ts, TimeStats::SetFrameRateVote frameRateVote = {}, - int32_t gameMode = kGameMode) { + GameMode gameMode = kGameMode) { for (size_t i = 0; i < N; i++, ts += 1000000) { setTimeStamp(sequence[i], id, frameNumber, ts, frameRateVote, gameMode); } @@ -203,7 +203,7 @@ static std::string genLayerName(int32_t layerId) { } void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts, - TimeStats::SetFrameRateVote frameRateVote, int32_t gameMode) { + TimeStats::SetFrameRateVote frameRateVote, GameMode gameMode) { switch (type) { case TimeStamp::POST: ASSERT_NO_FATAL_FAILURE(mTimeStats->setPostTime(id, frameNumber, genLayerName(id), @@ -1168,8 +1168,7 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { constexpr nsecs_t APP_DEADLINE_DELTA_3MS = 3'000'000; EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); - insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000, {}, - TimeStatsHelper::GameModeStandard); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000, {}, GameMode::Standard); for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) { mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire); } @@ -1182,42 +1181,39 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { TimeStats::SetFrameRateVote::FrameRateCompatibility::ExactOrMultiple, .seamlessness = TimeStats::SetFrameRateVote::Seamlessness::NotRequired, }; - insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, frameRate60, - TimeStatsHelper::GameModeStandard); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, frameRate60, GameMode::Standard); - mTimeStats->incrementJankyFrames( - {kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - TimeStatsHelper::GameModeStandard, JankType::SurfaceFlingerCpuDeadlineMissed, - DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS}); - mTimeStats->incrementJankyFrames( - {kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - TimeStatsHelper::GameModeStandard, JankType::SurfaceFlingerGpuDeadlineMissed, - DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - TimeStatsHelper::GameModeStandard, JankType::DisplayHAL, + GameMode::Standard, JankType::SurfaceFlingerCpuDeadlineMissed, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - TimeStatsHelper::GameModeStandard, - JankType::AppDeadlineMissed, DISPLAY_DEADLINE_DELTA, - DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS}); + GameMode::Standard, JankType::SurfaceFlingerGpuDeadlineMissed, + DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, + APP_DEADLINE_DELTA_3MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - TimeStatsHelper::GameModeStandard, - JankType::SurfaceFlingerScheduling, DISPLAY_DEADLINE_DELTA, - DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_2MS}); + GameMode::Standard, JankType::DisplayHAL, + DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, + APP_DEADLINE_DELTA_3MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - TimeStatsHelper::GameModeStandard, JankType::PredictionError, + GameMode::Standard, JankType::AppDeadlineMissed, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, - APP_DEADLINE_DELTA_2MS}); + APP_DEADLINE_DELTA_3MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - TimeStatsHelper::GameModeStandard, - JankType::AppDeadlineMissed | JankType::BufferStuffing, - DISPLAY_DEADLINE_DELTA, APP_DEADLINE_DELTA_2MS, + GameMode::Standard, JankType::SurfaceFlingerScheduling, + DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_2MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - TimeStatsHelper::GameModeStandard, JankType::None, + GameMode::Standard, JankType::PredictionError, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, - APP_DEADLINE_DELTA_3MS}); + APP_DEADLINE_DELTA_2MS}); + mTimeStats->incrementJankyFrames( + {kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), GameMode::Standard, + JankType::AppDeadlineMissed | JankType::BufferStuffing, DISPLAY_DEADLINE_DELTA, + APP_DEADLINE_DELTA_2MS, APP_DEADLINE_DELTA_2MS}); + mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + GameMode::Standard, JankType::None, DISPLAY_DEADLINE_DELTA, + DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS}); std::string pulledData; EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); @@ -1293,22 +1289,18 @@ TEST_F(TimeStatsTest, layerStatsCallback_multipleGameModes) { constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 3; EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); - insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000, {}, - TimeStatsHelper::GameModeStandard); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000, {}, GameMode::Standard); for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) { mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire); } for (size_t i = 0; i < BAD_DESIRED_PRESENT_FRAMES; i++) { mTimeStats->incrementBadDesiredPresent(LAYER_ID_0); } - insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, {}, - TimeStatsHelper::GameModeStandard); - - insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000, {}, - TimeStatsHelper::GameModePerformance); - insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 4000000, {}, TimeStatsHelper::GameModeBattery); - insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 5, 4000000, {}, TimeStatsHelper::GameModeBattery); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, {}, GameMode::Standard); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000, {}, GameMode::Performance); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 4000000, {}, GameMode::Battery); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 5, 4000000, {}, GameMode::Battery); std::string pulledData; EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h index 5aebd2f20e..0a69b562ab 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h +++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h @@ -41,19 +41,21 @@ public: MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t)); MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t)); MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, const std::shared_ptr&)); - MOCK_METHOD6(setPostTime, void(int32_t, uint64_t, const std::string&, uid_t, nsecs_t, int32_t)); + MOCK_METHOD(void, setPostTime, + (int32_t, uint64_t, const std::string&, uid_t, nsecs_t, GameMode), (override)); MOCK_METHOD2(incrementLatchSkipped, void(int32_t layerId, LatchSkipReason reason)); MOCK_METHOD1(incrementBadDesiredPresent, void(int32_t layerId)); MOCK_METHOD3(setLatchTime, void(int32_t, uint64_t, nsecs_t)); MOCK_METHOD3(setDesiredTime, void(int32_t, uint64_t, nsecs_t)); MOCK_METHOD3(setAcquireTime, void(int32_t, uint64_t, nsecs_t)); MOCK_METHOD3(setAcquireFence, void(int32_t, uint64_t, const std::shared_ptr&)); - MOCK_METHOD7(setPresentTime, - void(int32_t, uint64_t, nsecs_t, Fps, std::optional, SetFrameRateVote, - int32_t)); - MOCK_METHOD7(setPresentFence, - void(int32_t, uint64_t, const std::shared_ptr&, Fps, std::optional, - SetFrameRateVote, int32_t)); + MOCK_METHOD(void, setPresentTime, + (int32_t, uint64_t, nsecs_t, Fps, std::optional, SetFrameRateVote, GameMode), + (override)); + MOCK_METHOD(void, setPresentFence, + (int32_t, uint64_t, const std::shared_ptr&, Fps, std::optional, + SetFrameRateVote, GameMode), + (override)); MOCK_METHOD1(incrementJankyFrames, void(const JankyFramesInfo&)); MOCK_METHOD1(onDestroy, void(int32_t)); MOCK_METHOD2(removeTimeRecord, void(int32_t, uint64_t)); -- cgit v1.2.3-59-g8ed1b From cf4c9000f7aed5e6384f719c1f2bf5a84ad36756 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 19 Nov 2021 23:44:33 +0000 Subject: Fix compilation in SurfaceFlinger_DisplayModeSwitching.cpp Bug: 207167066 Change-Id: If422b93915650336851e1a726faeb302b86859cf Test: build --- .../tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp index 025edc2147..9796a7072a 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp @@ -20,7 +20,7 @@ #include "DisplayTransactionTestHelpers.h" -#include "Fps.h" +#include namespace android { namespace { -- cgit v1.2.3-59-g8ed1b From 2b80b386c4ed5a1b3240da32080280b0a1ec9cef Mon Sep 17 00:00:00 2001 From: Jay Wang Date: Fri, 19 Nov 2021 17:26:26 +0000 Subject: Revert "Remove x/y offset from MotionEntry" Revert submission 16295572 Reason for revert: DroidMonitor-triggered revert due to breakage bug http://b/207128427. BUG: 207128427 Reverted Changes: I65c284e5e:Input injection: Assume transformed values are in ... Ifd359ebb0:Remove x/y offset from MotionEntry Change-Id: Iab395d41d49db17c0a682bdd6c77fe2aacc004f4 --- include/input/Input.h | 5 +++-- libs/input/Input.cpp | 5 +++++ services/inputflinger/dispatcher/Entry.cpp | 5 ++++- services/inputflinger/dispatcher/Entry.h | 3 ++- services/inputflinger/dispatcher/InputDispatcher.cpp | 10 +++++----- services/inputflinger/dispatcher/InputState.cpp | 6 ++++-- 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index 1c79c4a21c..1e06257591 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -377,6 +377,7 @@ struct PointerCoords { // window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR // axes, however the window scaling will not. void scale(float globalScale, float windowXScale, float windowYScale); + void applyOffset(float xOffset, float yOffset); void transform(const ui::Transform& transform); @@ -566,7 +567,7 @@ public: inline float getYOffset() const { return mTransform.ty(); } - inline const ui::Transform& getTransform() const { return mTransform; } + inline ui::Transform getTransform() const { return mTransform; } inline float getXPrecision() const { return mXPrecision; } @@ -582,7 +583,7 @@ public: void setCursorPosition(float x, float y); - inline const ui::Transform& getRawTransform() const { return mRawTransform; } + ui::Transform getRawTransform() const { return mRawTransform; } static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); } diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 69ea7dfcb5..8974b22c86 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -343,6 +343,11 @@ void PointerCoords::scale(float globalScaleFactor, float windowXScale, float win scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_Y, windowYScale); } +void PointerCoords::applyOffset(float xOffset, float yOffset) { + setAxisValue(AMOTION_EVENT_AXIS_X, getX() + xOffset); + setAxisValue(AMOTION_EVENT_AXIS_Y, getY() + yOffset); +} + #ifdef __linux__ status_t PointerCoords::readFromParcel(Parcel* parcel) { bits = parcel->readInt64(); diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index 3d0818b738..1674afd02e 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -214,7 +214,7 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords) + const PointerCoords* pointerCoords, float xOffset, float yOffset) : EventEntry(id, Type::MOTION, eventTime, policyFlags), deviceId(deviceId), source(source), @@ -235,6 +235,9 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); this->pointerCoords[i].copyFrom(pointerCoords[i]); + if (xOffset || yOffset) { + this->pointerCoords[i].applyOffset(xOffset, yOffset); + } } } diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index 0f792967eb..477781a2ad 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -184,7 +184,8 @@ struct MotionEntry : EventEntry { int32_t metaState, int32_t buttonState, MotionClassification classification, int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, + float xOffset, float yOffset); std::string getDescription() const override; ~MotionEntry() override; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 04ff599f13..3fd1c8aa27 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -378,7 +378,7 @@ std::unique_ptr createDispatchEntry(const InputTarget& inputTarge motionEntry.yPrecision, motionEntry.xCursorPosition, motionEntry.yCursorPosition, motionEntry.downTime, motionEntry.pointerCount, motionEntry.pointerProperties, - pointerCoords.data()); + pointerCoords.data(), 0 /* xOffset */, 0 /* yOffset */); if (motionEntry.injectionState) { combinedMotionEntry->injectionState = motionEntry.injectionState; @@ -3752,7 +3752,7 @@ std::unique_ptr InputDispatcher::splitMotionEvent( originalMotionEntry.xCursorPosition, originalMotionEntry.yCursorPosition, originalMotionEntry.downTime, splitPointerCount, - splitPointerProperties, splitPointerCoords); + splitPointerProperties, splitPointerCoords, 0, 0); if (originalMotionEntry.injectionState) { splitMotionEntry->injectionState = originalMotionEntry.injectionState; @@ -3978,7 +3978,7 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { args->xPrecision, args->yPrecision, args->xCursorPosition, args->yCursorPosition, args->downTime, args->pointerCount, - args->pointerProperties, args->pointerCoords); + args->pointerProperties, args->pointerCoords, 0, 0); if (args->id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID && IdGenerator::getSource(args->id) == IdGenerator::Source::INPUT_READER && @@ -4208,7 +4208,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawXCursorPosition(), motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), - pointerProperties, samplePointerCoords); + pointerProperties, samplePointerCoords, 0, 0); transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(injectedEntry)); for (size_t i = motionEvent.getHistorySize(); i > 0; i--) { @@ -4228,7 +4228,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), pointerProperties, - samplePointerCoords); + samplePointerCoords, 0, 0); transformMotionEntryForInjectionLocked(*nextInjectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(nextInjectedEntry)); diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index ad3c6159ef..3bb0bc995c 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -296,7 +296,8 @@ std::vector> InputState::synthesizeCancelationEvents memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, memento.pointerCount, memento.pointerProperties, - memento.pointerCoords)); + memento.pointerCoords, 0 /*xOffset*/, + 0 /*yOffset*/)); } } return events; @@ -348,7 +349,8 @@ std::vector> InputState::synthesizePointerDownEvents AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, - pointerCount, pointerProperties, pointerCoords)); + pointerCount, pointerProperties, pointerCoords, + 0 /*xOffset*/, 0 /*yOffset*/)); } memento.firstNewPointerIdx = INVALID_POINTER_INDEX; -- cgit v1.2.3-59-g8ed1b From e1e23f40f3894b214d3599263fc0755a506ca5b0 Mon Sep 17 00:00:00 2001 From: Jay Wang Date: Fri, 19 Nov 2021 17:26:26 +0000 Subject: Revert "Input injection: Assume transformed values are in logica..." Revert submission 16295572 Reason for revert: DroidMonitor-triggered revert due to breakage bug http://b/207128427. BUG: 207128427 Reverted Changes: I65c284e5e:Input injection: Assume transformed values are in ... Ifd359ebb0:Remove x/y offset from MotionEntry Change-Id: I7beca684d557f9ea6416caa032af64ac94e0588a --- .../inputflinger/dispatcher/InputDispatcher.cpp | 55 ++++++++++++++-------- services/inputflinger/dispatcher/InputDispatcher.h | 4 +- .../inputflinger/tests/InputDispatcher_test.cpp | 27 ----------- 3 files changed, 36 insertions(+), 50 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 3fd1c8aa27..7f68d1b8b1 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -506,6 +506,12 @@ bool isConnectionResponsive(const Connection& connection) { return true; } +vec2 transformWithoutTranslation(const ui::Transform& transform, float x, float y) { + const vec2 transformedXy = transform.transform(x, y); + const vec2 transformedOrigin = transform.transform(0, 0); + return transformedXy - transformedOrigin; +} + // Returns true if the event type passed as argument represents a user activity. bool isUserActivityEvent(const EventEntry& eventEntry) { switch (eventEntry.type) { @@ -4208,8 +4214,10 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawXCursorPosition(), motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), - pointerProperties, samplePointerCoords, 0, 0); - transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform()); + pointerProperties, samplePointerCoords, + motionEvent.getXOffset(), + motionEvent.getYOffset()); + transformMotionEntryForInjectionLocked(*injectedEntry); injectedEntries.push(std::move(injectedEntry)); for (size_t i = motionEvent.getHistorySize(); i > 0; i--) { sampleEventTimes += 1; @@ -4228,9 +4236,9 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), pointerProperties, - samplePointerCoords, 0, 0); - transformMotionEntryForInjectionLocked(*nextInjectedEntry, - motionEvent.getTransform()); + samplePointerCoords, motionEvent.getXOffset(), + motionEvent.getYOffset()); + transformMotionEntryForInjectionLocked(*nextInjectedEntry); injectedEntries.push(std::move(nextInjectedEntry)); } break; @@ -4394,28 +4402,35 @@ void InputDispatcher::setInjectionResult(EventEntry& entry, } } -void InputDispatcher::transformMotionEntryForInjectionLocked( - MotionEntry& entry, const ui::Transform& injectedTransform) const { +void InputDispatcher::transformMotionEntryForInjectionLocked(MotionEntry& entry) const { + const bool isRelativeMouseEvent = isFromSource(entry.source, AINPUT_SOURCE_MOUSE_RELATIVE); + if (!isRelativeMouseEvent && !isFromSource(entry.source, AINPUT_SOURCE_CLASS_POINTER)) { + return; + } + // Input injection works in the logical display coordinate space, but the input pipeline works // display space, so we need to transform the injected events accordingly. const auto it = mDisplayInfos.find(entry.displayId); if (it == mDisplayInfos.end()) return; - const auto& transformToDisplay = it->second.transform.inverse() * injectedTransform; + const auto& transformToDisplay = it->second.transform.inverse(); for (uint32_t i = 0; i < entry.pointerCount; i++) { PointerCoords& pc = entry.pointerCoords[i]; - // Make a copy of the injected coords. We cannot change them in place because some of them - // are interdependent (for example, X coordinate might depend on the Y coordinate). - PointerCoords injectedCoords = entry.pointerCoords[i]; - - BitSet64 bits(injectedCoords.bits); - while (!bits.isEmpty()) { - const auto axis = static_cast(bits.clearFirstMarkedBit()); - const float value = - MotionEvent::calculateTransformedAxisValue(axis, entry.source, - transformToDisplay, injectedCoords); - pc.setAxisValue(axis, value); - } + const auto xy = isRelativeMouseEvent + ? transformWithoutTranslation(transformToDisplay, pc.getX(), pc.getY()) + : transformToDisplay.transform(pc.getXYValue()); + pc.setAxisValue(AMOTION_EVENT_AXIS_X, xy.x); + pc.setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y); + + // Axes with relative values never represent points on a screen, so they should never have + // translation applied. If a device does not report relative values, these values are always + // 0, and will remain unaffected by the following operation. + const auto rel = + transformWithoutTranslation(transformToDisplay, + pc.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), + pc.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)); + pc.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, rel.x); + pc.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, rel.y); } } diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 6f05670943..8a551cfca1 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -280,9 +280,7 @@ private: bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); void setInjectionResult(EventEntry& entry, android::os::InputEventInjectionResult injectionResult); - void transformMotionEntryForInjectionLocked(MotionEntry&, - const ui::Transform& injectedTransform) const - REQUIRES(mLock); + void transformMotionEntryForInjectionLocked(MotionEntry&) const REQUIRES(mLock); std::condition_variable mInjectionSyncFinished; void incrementPendingForegroundDispatches(EventEntry& entry); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index eaea4e26c4..515a01e137 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -2079,33 +2079,6 @@ TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) { secondWindow->assertNoEvents(); } -// Ensure that when a MotionEvent that has a custom transform is injected, the post-transformed -// event should be treated as being in the logical display space. -TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisplaySpace) { - auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); - - const std::array matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0}; - ui::Transform injectedEventTransform; - injectedEventTransform.set(matrix); - const vec2 expectedPoint{75, 55}; // The injected point in the logical display space. - const vec2 untransformedPoint = injectedEventTransform.inverse().transform(expectedPoint); - - MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .displayId(ADISPLAY_ID_DEFAULT) - .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) - .x(untransformedPoint.x) - .y(untransformedPoint.y)) - .build(); - event.transform(matrix); - - injectMotionEvent(mDispatcher, event, INJECT_EVENT_TIMEOUT, - InputEventInjectionSync::WAIT_FOR_RESULT); - - firstWindow->consumeMotionDown(); - secondWindow->assertNoEvents(); -} - TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) { auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); -- cgit v1.2.3-59-g8ed1b From 44036e24a77d5912ab4d9ff4227c4870bb9a7445 Mon Sep 17 00:00:00 2001 From: Alex Buynytskyy Date: Fri, 19 Nov 2021 08:58:23 -0800 Subject: Add packageName argument in preparation for per-package lock. Bug: 201090222 Test: presubmit Ignore-AOSP-First: AIDL changed, require simultaneous change to the framework Change-Id: I95dafcec16117fe76367458fe5e17009da80211d --- cmds/installd/InstalldNativeService.cpp | 62 ++++++++++++++++---------- cmds/installd/InstalldNativeService.h | 46 ++++++++++--------- cmds/installd/binder/android/os/IInstalld.aidl | 26 ++++++----- cmds/installd/tests/installd_dexopt_test.cpp | 3 +- 4 files changed, 79 insertions(+), 58 deletions(-) diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 5472da779a..afbd7dcef4 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -2494,35 +2494,33 @@ static const char* getCStr(const std::optional& data, const char* default_value = nullptr) { return data ? data->c_str() : default_value; } -binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t uid, - const std::optional& packageName, const std::string& instructionSet, - int32_t dexoptNeeded, const std::optional& outputPath, int32_t dexFlags, +binder::Status InstalldNativeService::dexopt( + const std::string& apkPath, int32_t uid, const std::string& packageName, + const std::string& instructionSet, int32_t dexoptNeeded, + const std::optional& outputPath, int32_t dexFlags, const std::string& compilerFilter, const std::optional& uuid, const std::optional& classLoaderContext, const std::optional& seInfo, bool downgrade, int32_t targetSdkVersion, const std::optional& profileName, const std::optional& dexMetadataPath, - const std::optional& compilationReason, - bool* aidl_return) { + const std::optional& compilationReason, bool* aidl_return) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PATH(apkPath); - if (packageName && *packageName != "*") { - CHECK_ARGUMENT_PACKAGE_NAME(*packageName); - } + CHECK_ARGUMENT_PACKAGE_NAME(packageName); CHECK_ARGUMENT_PATH(outputPath); CHECK_ARGUMENT_PATH(dexMetadataPath); std::lock_guard lock(mLock); const char* oat_dir = getCStr(outputPath); const char* instruction_set = instructionSet.c_str(); - if (oat_dir != nullptr && !createOatDir(oat_dir, instruction_set).isOk()) { + if (oat_dir != nullptr && !createOatDir(packageName, oat_dir, instruction_set).isOk()) { // Can't create oat dir - let dexopt use cache dir. oat_dir = nullptr; } const char* apk_path = apkPath.c_str(); - const char* pkgname = getCStr(packageName, "*"); + const char* pkgname = packageName.c_str(); const char* compiler_filter = compilerFilter.c_str(); const char* volume_uuid = getCStr(uuid); const char* class_loader_context = getCStr(classLoaderContext); @@ -2680,9 +2678,11 @@ binder::Status InstalldNativeService::restoreconAppData(const std::optional lock(mLock); @@ -2706,8 +2706,10 @@ binder::Status InstalldNativeService::createOatDir(const std::string& oatDir, return ok(); } -binder::Status InstalldNativeService::rmPackageDir(const std::string& packageDir) { +binder::Status InstalldNativeService::rmPackageDir(const std::string& packageName, + const std::string& packageDir) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PACKAGE_NAME(packageName); CHECK_ARGUMENT_PATH(packageDir); std::lock_guard lock(mLock); @@ -2720,9 +2722,12 @@ binder::Status InstalldNativeService::rmPackageDir(const std::string& packageDir return ok(); } -binder::Status InstalldNativeService::linkFile(const std::string& relativePath, - const std::string& fromBase, const std::string& toBase) { +binder::Status InstalldNativeService::linkFile(const std::string& packageName, + const std::string& relativePath, + const std::string& fromBase, + const std::string& toBase) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PACKAGE_NAME(packageName); CHECK_ARGUMENT_PATH(fromBase); CHECK_ARGUMENT_PATH(toBase); std::lock_guard lock(mLock); @@ -2750,9 +2755,12 @@ binder::Status InstalldNativeService::linkFile(const std::string& relativePath, return ok(); } -binder::Status InstalldNativeService::moveAb(const std::string& apkPath, - const std::string& instructionSet, const std::string& outputPath) { +binder::Status InstalldNativeService::moveAb(const std::string& packageName, + const std::string& apkPath, + const std::string& instructionSet, + const std::string& outputPath) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PACKAGE_NAME(packageName); CHECK_ARGUMENT_PATH(apkPath); CHECK_ARGUMENT_PATH(outputPath); std::lock_guard lock(mLock); @@ -2765,10 +2773,13 @@ binder::Status InstalldNativeService::moveAb(const std::string& apkPath, return success ? ok() : error(); } -binder::Status InstalldNativeService::deleteOdex(const std::string& apkPath, - const std::string& instructionSet, const std::optional& outputPath, - int64_t* _aidl_return) { +binder::Status InstalldNativeService::deleteOdex(const std::string& packageName, + const std::string& apkPath, + const std::string& instructionSet, + const std::optional& outputPath, + int64_t* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PACKAGE_NAME(packageName); CHECK_ARGUMENT_PATH(apkPath); CHECK_ARGUMENT_PATH(outputPath); std::lock_guard lock(mLock); @@ -2800,9 +2811,12 @@ struct fsverity_measurement { #endif -binder::Status InstalldNativeService::installApkVerity(const std::string& filePath, - android::base::unique_fd verityInputAshmem, int32_t contentSize) { +binder::Status InstalldNativeService::installApkVerity(const std::string& packageName, + const std::string& filePath, + android::base::unique_fd verityInputAshmem, + int32_t contentSize) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PACKAGE_NAME(packageName); CHECK_ARGUMENT_PATH(filePath); std::lock_guard lock(mLock); @@ -2882,9 +2896,11 @@ binder::Status InstalldNativeService::installApkVerity(const std::string& filePa return ok(); } -binder::Status InstalldNativeService::assertFsverityRootHashMatches(const std::string& filePath, +binder::Status InstalldNativeService::assertFsverityRootHashMatches( + const std::string& packageName, const std::string& filePath, const std::vector& expectedHash) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PACKAGE_NAME(packageName); CHECK_ARGUMENT_PATH(filePath); std::lock_guard lock(mLock); diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index 3fdb01ad8b..9e52323a56 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -110,16 +110,15 @@ public: int32_t appId, const std::string& seInfo, int32_t targetSdkVersion, const std::string& fromCodePath); - binder::Status dexopt(const std::string& apkPath, int32_t uid, - const std::optional& packageName, const std::string& instructionSet, - int32_t dexoptNeeded, const std::optional& outputPath, int32_t dexFlags, - const std::string& compilerFilter, const std::optional& uuid, - const std::optional& classLoaderContext, - const std::optional& seInfo, bool downgrade, - int32_t targetSdkVersion, const std::optional& profileName, - const std::optional& dexMetadataPath, - const std::optional& compilationReason, - bool* aidl_return); + binder::Status dexopt(const std::string& apkPath, int32_t uid, const std::string& packageName, + const std::string& instructionSet, int32_t dexoptNeeded, + const std::optional& outputPath, int32_t dexFlags, + const std::string& compilerFilter, const std::optional& uuid, + const std::optional& classLoaderContext, + const std::optional& seInfo, bool downgrade, + int32_t targetSdkVersion, const std::optional& profileName, + const std::optional& dexMetadataPath, + const std::optional& compilationReason, bool* aidl_return); binder::Status controlDexOptBlocking(bool block); @@ -143,22 +142,25 @@ public: binder::Status destroyProfileSnapshot(const std::string& packageName, const std::string& profileName); - binder::Status rmPackageDir(const std::string& packageDir); + binder::Status rmPackageDir(const std::string& packageName, const std::string& packageDir); binder::Status freeCache(const std::optional& uuid, int64_t targetFreeBytes, int32_t flags); binder::Status linkNativeLibraryDirectory(const std::optional& uuid, const std::string& packageName, const std::string& nativeLibPath32, int32_t userId); - binder::Status createOatDir(const std::string& oatDir, const std::string& instructionSet); - binder::Status linkFile(const std::string& relativePath, const std::string& fromBase, - const std::string& toBase); - binder::Status moveAb(const std::string& apkPath, const std::string& instructionSet, - const std::string& outputPath); - binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet, - const std::optional& outputPath, int64_t* _aidl_return); - binder::Status installApkVerity(const std::string& filePath, - android::base::unique_fd verityInput, int32_t contentSize); - binder::Status assertFsverityRootHashMatches(const std::string& filePath, - const std::vector& expectedHash); + binder::Status createOatDir(const std::string& packageName, const std::string& oatDir, + const std::string& instructionSet); + binder::Status linkFile(const std::string& packageName, const std::string& relativePath, + const std::string& fromBase, const std::string& toBase); + binder::Status moveAb(const std::string& packageName, const std::string& apkPath, + const std::string& instructionSet, const std::string& outputPath); + binder::Status deleteOdex(const std::string& packageName, const std::string& apkPath, + const std::string& instructionSet, + const std::optional& outputPath, int64_t* _aidl_return); + binder::Status installApkVerity(const std::string& packageName, const std::string& filePath, + android::base::unique_fd verityInput, int32_t contentSize); + binder::Status assertFsverityRootHashMatches(const std::string& packageName, + const std::string& filePath, + const std::vector& expectedHash); binder::Status reconcileSecondaryDexFile(const std::string& dexPath, const std::string& packageName, int32_t uid, const std::vector& isa, const std::optional& volumeUuid, int32_t storage_flag, bool* _aidl_return); diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index 9c51ff749d..e024548a2c 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -56,7 +56,7 @@ interface IInstalld { @utf8InCpp String seInfo, int targetSdkVersion, @utf8InCpp String fromCodePath); // Returns false if it is cancelled. Returns true if it is completed or have other errors. - boolean dexopt(@utf8InCpp String apkPath, int uid, @nullable @utf8InCpp String packageName, + boolean dexopt(@utf8InCpp String apkPath, int uid, @utf8InCpp String packageName, @utf8InCpp String instructionSet, int dexoptNeeded, @nullable @utf8InCpp String outputPath, int dexFlags, @utf8InCpp String compilerFilter, @nullable @utf8InCpp String uuid, @@ -85,20 +85,22 @@ interface IInstalld { @utf8InCpp String profileName, @utf8InCpp String classpath); void destroyProfileSnapshot(@utf8InCpp String packageName, @utf8InCpp String profileName); - void rmPackageDir(@utf8InCpp String packageDir); + void rmPackageDir(@utf8InCpp String packageName, @utf8InCpp String packageDir); void freeCache(@nullable @utf8InCpp String uuid, long targetFreeBytes, int flags); void linkNativeLibraryDirectory(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName, @utf8InCpp String nativeLibPath32, int userId); - void createOatDir(@utf8InCpp String oatDir, @utf8InCpp String instructionSet); - void linkFile(@utf8InCpp String relativePath, @utf8InCpp String fromBase, - @utf8InCpp String toBase); - void moveAb(@utf8InCpp String apkPath, @utf8InCpp String instructionSet, - @utf8InCpp String outputPath); - long deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet, - @nullable @utf8InCpp String outputPath); - void installApkVerity(@utf8InCpp String filePath, in FileDescriptor verityInput, - int contentSize); - void assertFsverityRootHashMatches(@utf8InCpp String filePath, in byte[] expectedHash); + void createOatDir(@utf8InCpp String packageName, @utf8InCpp String oatDir, + @utf8InCpp String instructionSet); + void linkFile(@utf8InCpp String packageName, @utf8InCpp String relativePath, + @utf8InCpp String fromBase, @utf8InCpp String toBase); + void moveAb(@utf8InCpp String packageName, @utf8InCpp String apkPath, + @utf8InCpp String instructionSet, @utf8InCpp String outputPath); + long deleteOdex(@utf8InCpp String packageName, @utf8InCpp String apkPath, + @utf8InCpp String instructionSet, @nullable @utf8InCpp String outputPath); + void installApkVerity(@utf8InCpp String packageName, @utf8InCpp String filePath, + in FileDescriptor verityInput, int contentSize); + void assertFsverityRootHashMatches(@utf8InCpp String packageName, @utf8InCpp String filePath, + in byte[] expectedHash); boolean reconcileSecondaryDexFile(@utf8InCpp String dexPath, @utf8InCpp String pkgName, int uid, in @utf8InCpp String[] isas, @nullable @utf8InCpp String volume_uuid, diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp index a937436f9c..bb36c395e1 100644 --- a/cmds/installd/tests/installd_dexopt_test.cpp +++ b/cmds/installd/tests/installd_dexopt_test.cpp @@ -635,6 +635,7 @@ protected: int64_t bytes_freed; binder::Status result = service_->deleteOdex( + package_name_, apk_path_, kRuntimeIsa, in_dalvik_cache ? std::nullopt : std::make_optional(app_oat_dir_.c_str()), @@ -729,7 +730,7 @@ TEST_F(DexoptTest, DexoptPrimaryPublic) { TEST_F(DexoptTest, DexoptPrimaryPublicCreateOatDir) { LOG(INFO) << "DexoptPrimaryPublic"; - ASSERT_BINDER_SUCCESS(service_->createOatDir(app_oat_dir_, kRuntimeIsa)); + ASSERT_BINDER_SUCCESS(service_->createOatDir(package_name_, app_oat_dir_, kRuntimeIsa)); CompilePrimaryDexOk("verify", DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC, app_oat_dir_.c_str(), -- cgit v1.2.3-59-g8ed1b From de69f8ae323ccfbf150a368145525b619568469c Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 18 Nov 2021 16:40:34 +0000 Subject: Reland "Change PointerController to display space" 259a2122aeafea0f20bfcc7c9bcd089511a5aa56 Bug: 188939842 Bug: 144544464 Bug: 206817973 Test: forrest run - CtsHardwareTestCases Change-Id: I8f0312a502ec5c79038ef1697cf2d5b23db9fcfc --- include/input/Input.h | 5 + libs/input/Input.cpp | 12 +-- .../include/PointerControllerInterface.h | 3 +- .../reader/mapper/CursorInputMapper.cpp | 17 +--- .../inputflinger/reader/mapper/CursorInputMapper.h | 2 - .../reader/mapper/TouchCursorInputMapperCommon.h | 20 ---- .../reader/mapper/TouchInputMapper.cpp | 110 +++++++-------------- .../inputflinger/reader/mapper/TouchInputMapper.h | 8 -- 8 files changed, 47 insertions(+), 130 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index 1e06257591..5242dcb476 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -201,6 +201,11 @@ namespace android { class Parcel; #endif +/* + * Apply the given transform to the point without applying any translation/offset. + */ +vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy); + const char* inputEventTypeToString(int32_t type); std::string inputEventSourceToString(int32_t source); diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 8974b22c86..cb93c92310 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -60,12 +60,6 @@ float transformAngle(const ui::Transform& transform, float angleRadians) { return atan2f(transformedPoint.x, -transformedPoint.y); } -vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) { - const vec2 transformedXy = transform.transform(xy); - const vec2 transformedOrigin = transform.transform(0, 0); - return transformedXy - transformedOrigin; -} - bool shouldDisregardTransformation(uint32_t source) { // Do not apply any transformations to axes from joysticks or touchpads. return isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK) || @@ -120,6 +114,12 @@ int32_t IdGenerator::nextId() const { // --- InputEvent --- +vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) { + const vec2 transformedXy = transform.transform(xy); + const vec2 transformedOrigin = transform.transform(0, 0); + return transformedXy - transformedOrigin; +} + const char* inputEventTypeToString(int32_t type) { switch (type) { case AINPUT_EVENT_TYPE_KEY: { diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h index b1069497d3..db4228d862 100644 --- a/services/inputflinger/include/PointerControllerInterface.h +++ b/services/inputflinger/include/PointerControllerInterface.h @@ -30,7 +30,8 @@ namespace android { * fingers * * The pointer controller is responsible for providing synchronization and for tracking - * display orientation changes if needed. + * display orientation changes if needed. It works in the display panel's coordinate space, which + * is the same coordinate space used by InputReader. */ class PointerControllerInterface { protected: diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index 15ba45945a..fcb56ef05c 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -188,8 +188,6 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { mOrientation = DISPLAY_ORIENTATION_0; - mDisplayWidth = 0; - mDisplayHeight = 0; const bool isOrientedDevice = (mParameters.orientationAware && mParameters.hasAssociatedDisplay); @@ -203,8 +201,6 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config->getDisplayViewportByType(ViewportType::INTERNAL); if (internalViewport) { mOrientation = getInverseRotation(internalViewport->orientation); - mDisplayWidth = internalViewport->deviceWidth; - mDisplayHeight = internalViewport->deviceHeight; } } @@ -335,14 +331,7 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER); if (moved) { - float dx = deltaX; - float dy = deltaY; - // Rotate the delta from InputReader's un-rotated coordinate space to - // PointerController's rotated coordinate space that is oriented with the - // viewport. - rotateDelta(getInverseRotation(mOrientation), &dx, &dy); - - mPointerController->move(dx, dy); + mPointerController->move(deltaX, deltaY); } if (buttonsChanged) { @@ -353,10 +342,6 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { } mPointerController->getPosition(&xCursorPosition, &yCursorPosition); - // Rotate the cursor position that is in PointerController's rotated coordinate space - // to InputReader's un-rotated coordinate space. - rotatePoint(mOrientation, xCursorPosition /*byRef*/, yCursorPosition /*byRef*/, - mDisplayWidth, mDisplayHeight); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h index 88e947f7d5..9a8ca01294 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.h +++ b/services/inputflinger/reader/mapper/CursorInputMapper.h @@ -105,8 +105,6 @@ private: VelocityControl mWheelYVelocityControl; int32_t mOrientation; - int32_t mDisplayWidth; - int32_t mDisplayHeight; std::shared_ptr mPointerController; diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h index 8c30e38908..31a3d2e172 100644 --- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h +++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h @@ -64,26 +64,6 @@ static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) { } } -// Rotates the given point (x, y) by the supplied orientation. The width and height are the -// dimensions of the surface prior to this rotation being applied. -static void rotatePoint(int32_t orientation, float& x, float& y, int32_t width, int32_t height) { - rotateDelta(orientation, &x, &y); - switch (orientation) { - case DISPLAY_ORIENTATION_90: - y += width; - break; - case DISPLAY_ORIENTATION_180: - x += width; - y += height; - break; - case DISPLAY_ORIENTATION_270: - x += height; - break; - default: - break; - } -} - // Returns true if the pointer should be reported as being down given the specified // button states. This determines whether the event is reported as a touch event. static bool isPointerDown(int32_t buttonState) { diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 3fe6fd130f..913c666a4a 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -1668,9 +1668,10 @@ void TouchInputMapper::updateTouchSpots() { mPointerController->fade(PointerControllerInterface::Transition::GRADUAL); mPointerController->setButtonState(mCurrentRawState.buttonState); - setTouchSpots(mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, - mCurrentCookedState.cookedPointerData.touchingIdBits, mViewport.displayId); + mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.touchingIdBits, + mViewport.displayId); } bool TouchInputMapper::isTouchScreen() { @@ -2410,9 +2411,10 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u } if (mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM) { - setTouchSpots(mPointerGesture.currentGestureCoords, - mPointerGesture.currentGestureIdToIndex, - mPointerGesture.currentGestureIdBits, mPointerController->getDisplayId()); + mPointerController->setSpots(mPointerGesture.currentGestureCoords, + mPointerGesture.currentGestureIdToIndex, + mPointerGesture.currentGestureIdBits, + mPointerController->getDisplayId()); } } else { mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER); @@ -2562,7 +2564,8 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u // the pointer is hovering again even if the user is not currently touching // the touch pad. This ensures that a view will receive a fresh hover enter // event after a tap. - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); PointerProperties pointerProperties; pointerProperties.clear(); @@ -2819,12 +2822,13 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi // Move the pointer using a relative motion. // When using spots, the click will occur at the position of the anchor // spot and all other spots will move there. - moveMouseCursor(deltaX, deltaY); + mPointerController->move(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); mPointerGesture.currentGestureMode = PointerGesture::Mode::BUTTON_CLICK_OR_DRAG; mPointerGesture.currentGestureIdBits.clear(); @@ -2850,7 +2854,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP_DRAG) && lastFingerCount == 1) { if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) { - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { #if DEBUG_GESTURES @@ -2918,7 +2923,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerGesture.currentGestureMode = PointerGesture::Mode::HOVER; if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP) { if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP_DRAG; @@ -2952,7 +2958,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi // Move the pointer using a relative motion. // When using spots, the hover or drag will occur at the position of the anchor spot. - moveMouseCursor(deltaX, deltaY); + mPointerController->move(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } @@ -2974,7 +2980,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi down = false; } - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); mPointerGesture.currentGestureIdBits.clear(); mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); @@ -3047,9 +3054,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mCurrentRawState.rawPointerData .getCentroidOfTouchingPointers(&mPointerGesture.referenceTouchX, &mPointerGesture.referenceTouchY); - auto [x, y] = getMouseCursorPosition(); - mPointerGesture.referenceGestureX = x; - mPointerGesture.referenceGestureY = y; + mPointerController->getPosition(&mPointerGesture.referenceGestureX, + &mPointerGesture.referenceGestureY); } // Clear the reference deltas for fingers not yet included in the reference calculation. @@ -3387,13 +3393,15 @@ void TouchInputMapper::dispatchPointerStylus(nsecs_t when, nsecs_t readTime, uin if (!mCurrentCookedState.stylusIdBits.isEmpty()) { uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit(); uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id]; - setMouseCursorPosition(mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(), - mCurrentCookedState.cookedPointerData.pointerCoords[index].getY()); + mPointerController + ->setPosition(mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(), + mCurrentCookedState.cookedPointerData.pointerCoords[index].getY()); hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id); down = !hovering; - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); mPointerSimple.currentCoords.copyFrom( mCurrentCookedState.cookedPointerData.pointerCoords[index]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); @@ -3434,7 +3442,7 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs_t readTime, uint rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY); mPointerVelocityControl.move(when, &deltaX, &deltaY); - moveMouseCursor(deltaX, deltaY); + mPointerController->move(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } @@ -3442,7 +3450,8 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs_t readTime, uint down = isPointerDown(mCurrentRawState.buttonState); hovering = !down; - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); mPointerSimple.currentCoords.copyFrom( mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); @@ -3482,7 +3491,8 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsecs_t readTime, uin } int32_t displayId = mPointerController->getDisplayId(); - auto [xCursorPosition, yCursorPosition] = getMouseCursorPosition(); + float xCursorPosition, yCursorPosition; + mPointerController->getPosition(&xCursorPosition, &yCursorPosition); if (mPointerSimple.down && !down) { mPointerSimple.down = false; @@ -3648,9 +3658,7 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, nsecs_t readTime, uint32_t p float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; if (mDeviceMode == DeviceMode::POINTER) { - auto [x, y] = getMouseCursorPosition(); - xCursorPosition = x; - yCursorPosition = y; + mPointerController->getPosition(&xCursorPosition, &yCursorPosition); } const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE); const int32_t deviceId = getDeviceId(); @@ -3999,56 +4007,4 @@ std::optional TouchInputMapper::getAssociatedDisplayId() { return std::nullopt; } -void TouchInputMapper::moveMouseCursor(float dx, float dy) const { - // Convert from InputReader's un-rotated coordinate space to PointerController's coordinate - // space that is oriented with the viewport. - rotateDelta(mViewport.orientation, &dx, &dy); - - mPointerController->move(dx, dy); -} - -std::pair TouchInputMapper::getMouseCursorPosition() const { - float x = 0; - float y = 0; - mPointerController->getPosition(&x, &y); - - if (!mViewport.isValid()) return {x, y}; - - // Convert from PointerController's rotated coordinate space that is oriented with the viewport - // to InputReader's un-rotated coordinate space. - const int32_t orientation = getInverseRotation(mViewport.orientation); - rotatePoint(orientation, x, y, mViewport.deviceWidth, mViewport.deviceHeight); - return {x, y}; -} - -void TouchInputMapper::setMouseCursorPosition(float x, float y) const { - // Convert from InputReader's un-rotated coordinate space to PointerController's rotated - // coordinate space that is oriented with the viewport. - rotatePoint(mViewport.orientation, x, y, mDisplayWidth, mDisplayHeight); - - mPointerController->setPosition(x, y); -} - -void TouchInputMapper::setTouchSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, - BitSet32 spotIdBits, int32_t displayId) { - std::array outSpotCoords{}; - - for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) { - const uint32_t index = spotIdToIndex[idBits.clearFirstMarkedBit()]; - float x = spotCoords[index].getX(); - float y = spotCoords[index].getY(); - float pressure = spotCoords[index].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); - - // Convert from InputReader's un-rotated coordinate space to PointerController's rotated - // coordinate space. - rotatePoint(mViewport.orientation, x, y, mDisplayWidth, mDisplayHeight); - - outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_X, x); - outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_Y, y); - outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); - } - - mPointerController->setSpots(outSpotCoords.data(), spotIdToIndex, spotIdBits, displayId); -} - } // namespace android diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index 496491b62d..9b020a609a 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -803,14 +803,6 @@ private: const char* modeToString(DeviceMode deviceMode); void rotateAndScale(float& x, float& y) const; - - // Wrapper methods for interfacing with PointerController. These are used to convert points - // between the coordinate spaces used by InputReader and PointerController, if they differ. - void moveMouseCursor(float dx, float dy) const; - std::pair getMouseCursorPosition() const; - void setMouseCursorPosition(float x, float y) const; - void setTouchSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, - BitSet32 spotIdBits, int32_t displayId); }; } // namespace android -- cgit v1.2.3-59-g8ed1b From 100264730172c6c4319c1d745cea53850afac5b8 Mon Sep 17 00:00:00 2001 From: Pablo Gamito Date: Mon, 22 Nov 2021 22:16:45 +0100 Subject: Only run surface stats callbacks on transaction complete Test: atest CtsWindowManagerDeviceTestCases:FrameMetricsTests Bug: 206956036 Change-Id: If31c4a6e2f391d8fd8e47a01d94653db584a5430 --- libs/gui/SurfaceComposerClient.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index b139cf126c..04fd8a28f5 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -352,6 +352,10 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener // through all until the SC is found. int32_t layerId = -1; for (auto callbackId : transactionStats.callbackIds) { + if (callbackId.type != CallbackId::Type::ON_COMPLETE) { + // We only want to run the stats callback for ON_COMPLETE + continue; + } sp sc = callbacksMap[callbackId].surfaceControls[surfaceStats.surfaceControl]; if (sc != nullptr) { @@ -360,7 +364,7 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener } } - { + if (layerId != -1) { // Acquire surface stats listener lock such that we guarantee that after calling // unregister, there won't be any further callback. std::scoped_lock lock(mSurfaceStatsListenerMutex); -- cgit v1.2.3-59-g8ed1b From ecc1f90e00ffd577a77ea7c763ee330c83626773 Mon Sep 17 00:00:00 2001 From: Huihong Luo Date: Sat, 20 Nov 2021 11:55:05 -0800 Subject: Migrate IRegionSamplingListener interface to AIDL This addresses security vulnerabilities due to hard coded binder interface. Bug: 195660647 Test: (1) atest RegionSamplingTest (2) install Google I/O 2019 app, tap Agenda menu, scrolling to examine the bottom horizontal bar color changes Change-Id: If2d33c5168b2df5fc7fd8f55e3bca75d3f385a89 --- libs/binder/include/binder/IInterface.h | 1 - libs/gui/Android.bp | 1 - libs/gui/IRegionSamplingListener.cpp | 64 ---------------------- libs/gui/ISurfaceComposer.cpp | 3 +- libs/gui/SurfaceComposerClient.cpp | 1 + .../aidl/android/gui/IRegionSamplingListener.aidl | 22 ++++++++ libs/gui/include/gui/IRegionSamplingListener.h | 43 --------------- libs/gui/include/gui/ISurfaceComposer.h | 3 +- libs/gui/include/gui/SurfaceComposerClient.h | 3 +- libs/gui/tests/RegionSampling_test.cpp | 7 ++- libs/gui/tests/SamplingDemo.cpp | 7 ++- libs/gui/tests/Surface_test.cpp | 1 + services/surfaceflinger/RegionSamplingThread.cpp | 1 - services/surfaceflinger/RegionSamplingThread.h | 4 +- services/surfaceflinger/SurfaceFlinger.h | 1 + 15 files changed, 42 insertions(+), 120 deletions(-) delete mode 100644 libs/gui/IRegionSamplingListener.cpp create mode 100644 libs/gui/aidl/android/gui/IRegionSamplingListener.aidl delete mode 100644 libs/gui/include/gui/IRegionSamplingListener.h diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h index 7d14315b01..415b19adf6 100644 --- a/libs/binder/include/binder/IInterface.h +++ b/libs/binder/include/binder/IInterface.h @@ -231,7 +231,6 @@ constexpr const char* const kManualInterfaces[] = { "android.gui.DisplayEventConnection", "android.gui.IConsumerListener", "android.gui.IGraphicBufferConsumer", - "android.gui.IRegionSamplingListener", "android.gui.ITransactionComposerListener", "android.gui.SensorEventConnection", "android.gui.SensorServer", diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 19a29c196d..fea9f810c2 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -184,7 +184,6 @@ cc_library_shared { "IGraphicBufferConsumer.cpp", "IGraphicBufferProducer.cpp", "IProducerListener.cpp", - "IRegionSamplingListener.cpp", "ISurfaceComposer.cpp", "ISurfaceComposerClient.cpp", "ITransactionCompletedListener.cpp", diff --git a/libs/gui/IRegionSamplingListener.cpp b/libs/gui/IRegionSamplingListener.cpp deleted file mode 100644 index 40cbfceaf7..0000000000 --- a/libs/gui/IRegionSamplingListener.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "IRegionSamplingListener" -//#define LOG_NDEBUG 0 - -#include - -namespace android { - -namespace { // Anonymous - -enum class Tag : uint32_t { - ON_SAMPLE_COLLECTED = IBinder::FIRST_CALL_TRANSACTION, - LAST = ON_SAMPLE_COLLECTED, -}; - -} // Anonymous namespace - -class BpRegionSamplingListener : public SafeBpInterface { -public: - explicit BpRegionSamplingListener(const sp& impl) - : SafeBpInterface(impl, "BpRegionSamplingListener") {} - - ~BpRegionSamplingListener() override; - - void onSampleCollected(float medianLuma) override { - callRemoteAsync(Tag::ON_SAMPLE_COLLECTED, medianLuma); - } -}; - -// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see -// clang warning -Wweak-vtables) -BpRegionSamplingListener::~BpRegionSamplingListener() = default; - -IMPLEMENT_META_INTERFACE(RegionSamplingListener, "android.gui.IRegionSamplingListener"); - -status_t BnRegionSamplingListener::onTransact(uint32_t code, const Parcel& data, Parcel* reply, - uint32_t flags) { - if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast(Tag::LAST)) { - return BBinder::onTransact(code, data, reply, flags); - } - auto tag = static_cast(code); - switch (tag) { - case Tag::ON_SAMPLE_COLLECTED: - return callLocalAsync(data, reply, &IRegionSamplingListener::onSampleCollected); - } -} - -} // namespace android diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 02950995af..a90f7559b3 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -17,13 +17,13 @@ // tag as surfaceflinger #define LOG_TAG "SurfaceFlinger" +#include #include #include #include #include #include #include -#include #include #include #include @@ -44,6 +44,7 @@ namespace android { +using gui::IRegionSamplingListener; using gui::IWindowInfosListener; using ui::ColorMode; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index b139cf126c..f6253a256c 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -53,6 +53,7 @@ namespace android { using gui::FocusRequest; +using gui::IRegionSamplingListener; using gui::WindowInfo; using gui::WindowInfoHandle; using gui::WindowInfosListener; diff --git a/libs/gui/aidl/android/gui/IRegionSamplingListener.aidl b/libs/gui/aidl/android/gui/IRegionSamplingListener.aidl new file mode 100644 index 0000000000..00a3959d79 --- /dev/null +++ b/libs/gui/aidl/android/gui/IRegionSamplingListener.aidl @@ -0,0 +1,22 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.gui; + +/** @hide */ +oneway interface IRegionSamplingListener { + void onSampleCollected(float medianLuma); +} diff --git a/libs/gui/include/gui/IRegionSamplingListener.h b/libs/gui/include/gui/IRegionSamplingListener.h deleted file mode 100644 index 1803d9a1da..0000000000 --- a/libs/gui/include/gui/IRegionSamplingListener.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2019 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 -#include - -#include -#include - -namespace android { - -class IRegionSamplingListener : public IInterface { -public: - DECLARE_META_INTERFACE(RegionSamplingListener) - - virtual void onSampleCollected(float medianLuma) = 0; -}; - -class BnRegionSamplingListener : public SafeBnInterface { -public: - BnRegionSamplingListener() - : SafeBnInterface("BnRegionSamplingListener") {} - - status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, - uint32_t flags = 0) override; -}; - -} // namespace android diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index e0183adbe6..e1e9182056 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -63,10 +64,10 @@ class HdrCapabilities; class IDisplayEventConnection; class IGraphicBufferProducer; class ISurfaceComposerClient; -class IRegionSamplingListener; class Rect; enum class FrameEvent; +using gui::IRegionSamplingListener; using gui::IScreenCaptureListener; namespace ui { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index e05c3646c6..0fe1253f94 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -51,10 +51,11 @@ namespace android { class HdrCapabilities; class ISurfaceComposerClient; class IGraphicBufferProducer; -class IRegionSamplingListener; class ITunnelModeEnabledListener; class Region; +using gui::IRegionSamplingListener; + struct SurfaceControlStats { SurfaceControlStats(const sp& sc, nsecs_t latchTime, nsecs_t acquireTime, const sp& presentFence, const sp& prevReleaseFence, diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp index 6746b0a827..c9106bed4c 100644 --- a/libs/gui/tests/RegionSampling_test.cpp +++ b/libs/gui/tests/RegionSampling_test.cpp @@ -17,9 +17,9 @@ #include #include +#include #include #include -#include #include #include #include @@ -135,12 +135,13 @@ private: std::atomic poll_{true}; }; -struct Listener : BnRegionSamplingListener { - void onSampleCollected(float medianLuma) override { +struct Listener : android::gui::BnRegionSamplingListener { + binder::Status onSampleCollected(float medianLuma) override { std::unique_lock lk(mutex); received = true; mLuma = medianLuma; cv.notify_all(); + return binder::Status::ok(); }; bool wait_event(std::chrono::milliseconds timeout) { std::unique_lock lk(mutex); diff --git a/libs/gui/tests/SamplingDemo.cpp b/libs/gui/tests/SamplingDemo.cpp index 0cd150d3cb..a083a228a6 100644 --- a/libs/gui/tests/SamplingDemo.cpp +++ b/libs/gui/tests/SamplingDemo.cpp @@ -20,9 +20,9 @@ #include #include +#include #include #include -#include #include #include #include @@ -33,7 +33,7 @@ using namespace std::chrono_literals; namespace android { -class Button : public BnRegionSamplingListener { +class Button : public gui::BnRegionSamplingListener { public: Button(const char* name, const Rect& samplingArea) { sp client = new SurfaceComposerClient; @@ -99,9 +99,10 @@ private: .apply(); } - void onSampleCollected(float medianLuma) override { + binder::Status onSampleCollected(float medianLuma) override { ATRACE_CALL(); setColor(medianLuma); + return binder::Status::ok(); } sp mClient; diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index b2baea6aba..e0c2aa7181 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -45,6 +45,7 @@ using namespace std::chrono_literals; // retrieve wide-color and hdr settings from configstore using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; +using gui::IRegionSamplingListener; using ui::ColorMode; using Transaction = SurfaceComposerClient::Transaction; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 32585dd9ac..da8c3e062c 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h index f715309b2e..686b4b1e1f 100644 --- a/services/surfaceflinger/RegionSamplingThread.h +++ b/services/surfaceflinger/RegionSamplingThread.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include #include @@ -34,12 +35,13 @@ namespace android { -class IRegionSamplingListener; class Layer; class Scheduler; class SurfaceFlinger; struct SamplingOffsetCallback; +using gui::IRegionSamplingListener; + float sampleArea(const uint32_t* data, int32_t width, int32_t height, int32_t stride, uint32_t orientation, const Rect& area); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 7339b3bc3d..1545c0004f 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -105,6 +105,7 @@ class TimeStats; class FrameTracer; class WindowInfosListenerInvoker; +using gui::IRegionSamplingListener; using gui::ScreenCaptureResults; namespace frametimeline { -- cgit v1.2.3-59-g8ed1b From fbfa572245e430392f779edbb01b3b18e1b2ed82 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Tue, 16 Nov 2021 02:45:54 +0000 Subject: Allow touch split enabled when no window touched If no window can be touched by first touch down, it would still deliver the event to the gesture monitor. So before gesture monitor pilfer the touch, if a new window supports split touch, it can't recevied the new point down event cause device looks unresponsive. Test: atest inputflinger_test Bug: 201647070 Change-Id: Ib0734ef7082bf673afb11eef9ec7bdb0b3f103ec --- .../inputflinger/dispatcher/InputDispatcher.cpp | 7 +- .../inputflinger/tests/InputDispatcher_test.cpp | 92 ++++++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index d5d906b335..4b07a214be 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2103,7 +2103,7 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( const std::vector newGestureMonitors = isDown ? selectResponsiveMonitorsLocked( getValueByKey(mGestureMonitorsByDisplay, displayId)) - : std::vector{}; + : tempTouchState.gestureMonitors; if (newTouchedWindowHandle == nullptr && newGestureMonitors.empty()) { ALOGI("Dropping event because there is no touchable window or gesture monitor at " @@ -2139,6 +2139,10 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( pointerIds.markBit(pointerId); } tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); + } else if (tempTouchState.windows.empty()) { + // If no window is touched, set split to true. This will allow the next pointer down to + // be delivered to a new window which supports split touch. + tempTouchState.split = true; } tempTouchState.addGestureMonitors(newGestureMonitors); @@ -5546,6 +5550,7 @@ status_t InputDispatcher::pilferPointers(const sp& token) { canceledWindows.c_str()); // Then clear the current touch state so we stop dispatching to them as well. + state.split = false; state.filterNonMonitors(); } return OK; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index ffacfb1b1f..39c52628d4 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -2766,6 +2766,13 @@ public: expectedDisplayId, expectedFlags); } + void consumeMotionPointerDown(int32_t pointerIdx) { + int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN | + (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, ADISPLAY_ID_DEFAULT, + 0 /*expectedFlags*/); + } + MotionEvent* consumeMotion() { InputEvent* event = mInputReceiver->consume(); if (!event) { @@ -2974,6 +2981,91 @@ TEST_F(InputDispatcherTest, TestMoveEvent) { 0 /*expectedFlags*/); } +TEST_F(InputDispatcherTest, GestureMonitor_SplitIfNoWindowTouched) { + FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT, + true /*isGestureMonitor*/); + + std::shared_ptr application = std::make_shared(); + // Create a non touch modal window that supports split touch + sp window = + new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 100, 100)); + window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + + // First finger down, no window touched. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 200})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); + window->assertNoEvents(); + + // Second finger down on window, the window should receive touch down. + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(100) + .y(200)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + window->consumeMotionDown(ADISPLAY_ID_DEFAULT); + monitor.consumeMotionPointerDown(1 /* pointerIndex */); +} + +TEST_F(InputDispatcherTest, GestureMonitor_NoSplitAfterPilfer) { + FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT, + true /*isGestureMonitor*/); + + std::shared_ptr application = std::make_shared(); + // Create a non touch modal window that supports split touch + sp window = + new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 100, 100)); + window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + + // First finger down, no window touched. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 200})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); + window->assertNoEvents(); + + // Gesture monitor pilfer the pointers. + mDispatcher->pilferPointers(monitor.getToken()); + + // Second finger down on window, the window should not receive touch down. + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(100) + .y(200)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + window->assertNoEvents(); + monitor.consumeMotionPointerDown(1 /* pointerIndex */); +} + /** * Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to * the device default right away. In the test scenario, we check both the default value, -- cgit v1.2.3-59-g8ed1b From 2ea44b9a14c603cc868a223091e23c70cc6abf38 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Tue, 23 Nov 2021 07:42:21 +0000 Subject: Should only add gesture monitors when first down To prevent adding the duplicated gesture monitors when next pointer down. Test: atest inputflinger_test Bug: 201647070 Change-Id: Ia3a678085a95dfcb14b35fb8f4b52920054c6339 --- services/inputflinger/dispatcher/InputDispatcher.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 4b07a214be..c9397c350b 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2144,8 +2144,9 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( // be delivered to a new window which supports split touch. tempTouchState.split = true; } - - tempTouchState.addGestureMonitors(newGestureMonitors); + if (isDown) { + tempTouchState.addGestureMonitors(newGestureMonitors); + } } else { /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ -- cgit v1.2.3-59-g8ed1b From 779447d9647a3fec774c06056dde4b916300827f Mon Sep 17 00:00:00 2001 From: Alex Buynytskyy Date: Mon, 22 Nov 2021 17:06:53 -0800 Subject: Enable granular locks for InstallD. Bug: 201090222 Test: atest PackageManagerShellCommandTest PackageManagerShellCommandIncrementalTest installd_service_test installd_cache_test installd_utils_test Ignore-AOSP-First: packageNames are missing in AOSP Change-Id: I5f9b4fffc99d1196f9b267961b85edd9786493b2 --- cmds/installd/InstalldNativeService.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 9c5bf4d025..b78a764e3d 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -77,7 +77,7 @@ #define LOG_TAG "installd" #endif -// #define GRANULAR_LOCKS +#define GRANULAR_LOCKS using android::base::ParseUint; using android::base::StringPrintf; -- cgit v1.2.3-59-g8ed1b From ea5745afb64f0f71ccbc36d617a73d0ce0db2e9f Mon Sep 17 00:00:00 2001 From: Trevor David Black Date: Tue, 23 Nov 2021 17:27:23 +0000 Subject: Make BT709 support conditional on swapchain ext enable Bug: 203533233 Test: build Change-Id: I5f36059a06a92216bc83e3e794f7992ea3ce8048 --- vulkan/libvulkan/swapchain.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index e89a49b04c..54b10b1127 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -720,10 +720,10 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, if (err) { return VK_ERROR_SURFACE_LOST_KHR; } - ALOGV("wide_color_support is: %d", wide_color_support); - wide_color_support = - wide_color_support && + bool swapchain_ext = instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace); + ALOGV("wide_color_support is: %d", wide_color_support); + wide_color_support = wide_color_support && swapchain_ext; AHardwareBuffer_Desc desc = {}; desc.width = 1; @@ -736,8 +736,12 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, // We must support R8G8B8A8 std::vector all_formats = { {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, - {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, - {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_BT709_LINEAR_EXT}}; + {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}}; + + if (swapchain_ext) { + all_formats.emplace_back(VkSurfaceFormatKHR{ + VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_BT709_LINEAR_EXT}); + } if (wide_color_support) { all_formats.emplace_back(VkSurfaceFormatKHR{ -- cgit v1.2.3-59-g8ed1b From 6fac52325372298c094d3fd1ae0710dfff5e5796 Mon Sep 17 00:00:00 2001 From: Huihong Luo Date: Mon, 22 Nov 2021 16:05:23 -0800 Subject: Migrate IDisplayEventConnection interface to AIDL This addresses security vulnerabilities due to hard coded binder interface. Bug: 195660647 Test: atest services/surfaceflinger/tests/unittests/SchedulerTest.cpp Change-Id: I948e97e37056286d54623ca6232580187b138e62 --- libs/binder/include/binder/IInterface.h | 1 - libs/gui/Android.bp | 1 - libs/gui/DisplayEventReceiver.cpp | 1 - libs/gui/IDisplayEventConnection.cpp | 80 ---------------------- libs/gui/ISurfaceComposer.cpp | 3 +- libs/gui/aidl/android/gui/BitTube.aidl | 19 +++++ .../aidl/android/gui/IDisplayEventConnection.aidl | 41 +++++++++++ libs/gui/include/gui/DisplayEventReceiver.h | 2 +- libs/gui/include/gui/IDisplayEventConnection.h | 65 ------------------ libs/gui/include/gui/ISurfaceComposer.h | 3 +- libs/gui/tests/Surface_test.cpp | 3 +- services/surfaceflinger/Scheduler/EventThread.cpp | 13 ++-- services/surfaceflinger/Scheduler/EventThread.h | 10 +-- services/surfaceflinger/Scheduler/MessageQueue.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 3 +- .../tests/unittests/SchedulerTest.cpp | 6 +- 16 files changed, 85 insertions(+), 168 deletions(-) delete mode 100644 libs/gui/IDisplayEventConnection.cpp create mode 100644 libs/gui/aidl/android/gui/BitTube.aidl create mode 100644 libs/gui/aidl/android/gui/IDisplayEventConnection.aidl delete mode 100644 libs/gui/include/gui/IDisplayEventConnection.h diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h index 415b19adf6..f5abb859bc 100644 --- a/libs/binder/include/binder/IInterface.h +++ b/libs/binder/include/binder/IInterface.h @@ -228,7 +228,6 @@ constexpr const char* const kManualInterfaces[] = { "android.gfx.tests.IIPCTest", "android.gfx.tests.ISafeInterfaceTest", "android.graphicsenv.IGpuService", - "android.gui.DisplayEventConnection", "android.gui.IConsumerListener", "android.gui.IGraphicBufferConsumer", "android.gui.ITransactionComposerListener", diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index fea9f810c2..c5dec19582 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -180,7 +180,6 @@ cc_library_shared { "FrameTimelineInfo.cpp", "GLConsumer.cpp", "IConsumerListener.cpp", - "IDisplayEventConnection.cpp", "IGraphicBufferConsumer.cpp", "IGraphicBufferProducer.cpp", "IProducerListener.cpp", diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp index 03b33c7330..b916e48f79 100644 --- a/libs/gui/DisplayEventReceiver.cpp +++ b/libs/gui/DisplayEventReceiver.cpp @@ -19,7 +19,6 @@ #include #include -#include #include #include diff --git a/libs/gui/IDisplayEventConnection.cpp b/libs/gui/IDisplayEventConnection.cpp deleted file mode 100644 index c0e246fa15..0000000000 --- a/libs/gui/IDisplayEventConnection.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2011 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 - -#include - -namespace android { - -namespace { // Anonymous - -enum class Tag : uint32_t { - STEAL_RECEIVE_CHANNEL = IBinder::FIRST_CALL_TRANSACTION, - SET_VSYNC_RATE, - REQUEST_NEXT_VSYNC, - LAST = REQUEST_NEXT_VSYNC, -}; - -} // Anonymous namespace - -class BpDisplayEventConnection : public SafeBpInterface { -public: - explicit BpDisplayEventConnection(const sp& impl) - : SafeBpInterface(impl, "BpDisplayEventConnection") {} - - ~BpDisplayEventConnection() override; - - status_t stealReceiveChannel(gui::BitTube* outChannel) override { - return callRemote(Tag::STEAL_RECEIVE_CHANNEL, - outChannel); - } - - status_t setVsyncRate(uint32_t count) override { - return callRemote(Tag::SET_VSYNC_RATE, - count); - } - - void requestNextVsync() override { - callRemoteAsync( - Tag::REQUEST_NEXT_VSYNC); - } -}; - -// Out-of-line virtual method definition to trigger vtable emission in this translation unit (see -// clang warning -Wweak-vtables) -BpDisplayEventConnection::~BpDisplayEventConnection() = default; - -IMPLEMENT_META_INTERFACE(DisplayEventConnection, "android.gui.DisplayEventConnection"); - -status_t BnDisplayEventConnection::onTransact(uint32_t code, const Parcel& data, Parcel* reply, - uint32_t flags) { - if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast(Tag::LAST)) { - return BBinder::onTransact(code, data, reply, flags); - } - auto tag = static_cast(code); - switch (tag) { - case Tag::STEAL_RECEIVE_CHANNEL: - return callLocal(data, reply, &IDisplayEventConnection::stealReceiveChannel); - case Tag::SET_VSYNC_RATE: - return callLocal(data, reply, &IDisplayEventConnection::setVsyncRate); - case Tag::REQUEST_NEXT_VSYNC: - return callLocalAsync(data, reply, &IDisplayEventConnection::requestNextVsync); - } -} - -} // namespace android diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index a90f7559b3..7f73013f6e 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -17,12 +17,12 @@ // tag as surfaceflinger #define LOG_TAG "SurfaceFlinger" +#include #include #include #include #include #include -#include #include #include #include @@ -44,6 +44,7 @@ namespace android { +using gui::IDisplayEventConnection; using gui::IRegionSamplingListener; using gui::IWindowInfosListener; using ui::ColorMode; diff --git a/libs/gui/aidl/android/gui/BitTube.aidl b/libs/gui/aidl/android/gui/BitTube.aidl new file mode 100644 index 0000000000..6b0595ec66 --- /dev/null +++ b/libs/gui/aidl/android/gui/BitTube.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.gui; + +parcelable BitTube cpp_header "private/gui/BitTube.h"; diff --git a/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl b/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl new file mode 100644 index 0000000000..9f41593539 --- /dev/null +++ b/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl @@ -0,0 +1,41 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.gui; + +import android.gui.BitTube; + +/** @hide */ +interface IDisplayEventConnection { + /* + * stealReceiveChannel() returns a BitTube to receive events from. Only the receive file + * descriptor of outChannel will be initialized, and this effectively "steals" the receive + * channel from the remote end (such that the remote end can only use its send channel). + */ + void stealReceiveChannel(out BitTube outChannel); + + /* + * setVsyncRate() sets the vsync event delivery rate. A value of 1 returns every vsync event. + * A value of 2 returns every other event, etc. A value of 0 returns no event unless + * requestNextVsync() has been called. + */ + void setVsyncRate(in int count); + + /* + * requestNextVsync() schedules the next vsync event. It has no effect if the vsync rate is > 0. + */ + oneway void requestNextVsync(); // Asynchronous +} diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index ca368433b1..456bbfb611 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -33,7 +33,7 @@ namespace android { // ---------------------------------------------------------------------------- -class IDisplayEventConnection; +using gui::IDisplayEventConnection; namespace gui { class BitTube; diff --git a/libs/gui/include/gui/IDisplayEventConnection.h b/libs/gui/include/gui/IDisplayEventConnection.h deleted file mode 100644 index cff22a368a..0000000000 --- a/libs/gui/include/gui/IDisplayEventConnection.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2011 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 -#include -#include -#include - -#include - -namespace android { - -namespace gui { -class BitTube; -} // namespace gui - -class IDisplayEventConnection : public IInterface { -public: - DECLARE_META_INTERFACE(DisplayEventConnection) - - /* - * stealReceiveChannel() returns a BitTube to receive events from. Only the receive file - * descriptor of outChannel will be initialized, and this effectively "steals" the receive - * channel from the remote end (such that the remote end can only use its send channel). - */ - virtual status_t stealReceiveChannel(gui::BitTube* outChannel) = 0; - - /* - * setVsyncRate() sets the vsync event delivery rate. A value of 1 returns every vsync event. - * A value of 2 returns every other event, etc. A value of 0 returns no event unless - * requestNextVsync() has been called. - */ - virtual status_t setVsyncRate(uint32_t count) = 0; - - /* - * requestNextVsync() schedules the next vsync event. It has no effect if the vsync rate is > 0. - */ - virtual void requestNextVsync() = 0; // Asynchronous -}; - -class BnDisplayEventConnection : public SafeBnInterface { -public: - BnDisplayEventConnection() - : SafeBnInterface("BnDisplayEventConnection") {} - - status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, - uint32_t flags = 0) override; -}; - -} // namespace android diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index e1e9182056..2546e4c753 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include #include @@ -61,12 +62,12 @@ struct InputWindowCommands; struct LayerCaptureArgs; class LayerDebugInfo; class HdrCapabilities; -class IDisplayEventConnection; class IGraphicBufferProducer; class ISurfaceComposerClient; class Rect; enum class FrameEvent; +using gui::IDisplayEventConnection; using gui::IRegionSamplingListener; using gui::IScreenCaptureListener; diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index e0c2aa7181..d6ac3f9745 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -19,11 +19,11 @@ #include #include +#include #include #include #include #include -#include #include #include #include @@ -45,6 +45,7 @@ using namespace std::chrono_literals; // retrieve wide-color and hdr settings from configstore using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; +using gui::IDisplayEventConnection; using gui::IRegionSamplingListener; using ui::ColorMode; diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 455289ff96..627c49a853 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -170,20 +170,21 @@ void EventThreadConnection::onFirstRef() { mEventThread->registerDisplayEventConnection(this); } -status_t EventThreadConnection::stealReceiveChannel(gui::BitTube* outChannel) { +binder::Status EventThreadConnection::stealReceiveChannel(gui::BitTube* outChannel) { outChannel->setReceiveFd(mChannel.moveReceiveFd()); outChannel->setSendFd(base::unique_fd(dup(mChannel.getSendFd()))); - return NO_ERROR; + return binder::Status::ok(); } -status_t EventThreadConnection::setVsyncRate(uint32_t rate) { - mEventThread->setVsyncRate(rate, this); - return NO_ERROR; +binder::Status EventThreadConnection::setVsyncRate(int rate) { + mEventThread->setVsyncRate(static_cast(rate), this); + return binder::Status::ok(); } -void EventThreadConnection::requestNextVsync() { +binder::Status EventThreadConnection::requestNextVsync() { ATRACE_NAME("requestNextVsync"); mEventThread->requestNextVsync(this); + return binder::Status::ok(); } status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) { diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index de435708a6..fa9af098f6 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -17,8 +17,8 @@ #pragma once #include +#include #include -#include #include #include #include @@ -80,7 +80,7 @@ public: virtual void dump(std::string& result) const = 0; }; -class EventThreadConnection : public BnDisplayEventConnection { +class EventThreadConnection : public gui::BnDisplayEventConnection { public: EventThreadConnection(EventThread*, uid_t callingUid, ResyncCallback, ISurfaceComposer::EventRegistrationFlags eventRegistration = {}); @@ -88,9 +88,9 @@ public: virtual status_t postEvent(const DisplayEventReceiver::Event& event); - status_t stealReceiveChannel(gui::BitTube* outChannel) override; - status_t setVsyncRate(uint32_t rate) override; - void requestNextVsync() override; // asynchronous + binder::Status stealReceiveChannel(gui::BitTube* outChannel) override; + binder::Status setVsyncRate(int rate) override; + binder::Status requestNextVsync() override; // asynchronous // Called in response to requestNextVsync. const ResyncCallback resyncCallback; diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h index dd69d60580..9532e26a9c 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.h +++ b/services/surfaceflinger/Scheduler/MessageQueue.h @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 14761ea7ea..08d85275fe 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -51,7 +52,6 @@ #include #include #include -#include #include #include #include @@ -169,6 +169,7 @@ using namespace android::sysprop; using android::hardware::power::Boost; using base::StringAppendF; using gui::DisplayInfo; +using gui::IDisplayEventConnection; using gui::IWindowInfosListener; using gui::WindowInfo; using ui::ColorMode; diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index a6fd378d3d..f48abb7519 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -48,9 +48,9 @@ protected: : EventThreadConnection(eventThread, /*callingUid=*/0, ResyncCallback()) {} ~MockEventThreadConnection() = default; - MOCK_METHOD1(stealReceiveChannel, status_t(gui::BitTube* outChannel)); - MOCK_METHOD1(setVsyncRate, status_t(uint32_t count)); - MOCK_METHOD0(requestNextVsync, void()); + MOCK_METHOD1(stealReceiveChannel, binder::Status(gui::BitTube* outChannel)); + MOCK_METHOD1(setVsyncRate, binder::Status(int count)); + MOCK_METHOD0(requestNextVsync, binder::Status()); }; SchedulerTest(); -- cgit v1.2.3-59-g8ed1b From 42a27b5657975485a72033736f37bfe6de0e21a8 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 18 Nov 2021 15:35:22 -0800 Subject: SF: Update InputFlinger outside main thread Avoids parceling data inside main thread and hot path. Also avoids any binder contention with one way binder calls. See bug for more details. Bug: 206380307 Test: presubmit Test: systrace Change-Id: I4f8640587c821ac471559f1e6d2fbe41a8e64c87 --- libs/gui/LayerState.cpp | 4 +- services/surfaceflinger/BackgroundExecutor.cpp | 8 ++-- services/surfaceflinger/BackgroundExecutor.h | 7 +-- services/surfaceflinger/SurfaceFlinger.cpp | 61 ++++++++++++++++---------- services/surfaceflinger/SurfaceFlinger.h | 4 +- 5 files changed, 52 insertions(+), 32 deletions(-) diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index f848e4ffde..bb7e1a48f7 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -546,9 +546,7 @@ bool InputWindowCommands::merge(const InputWindowCommands& other) { } bool InputWindowCommands::empty() const { - bool empty = true; - empty = focusRequests.empty() && !syncInputWindows; - return empty; + return focusRequests.empty() && !syncInputWindows; } void InputWindowCommands::clear() { diff --git a/services/surfaceflinger/BackgroundExecutor.cpp b/services/surfaceflinger/BackgroundExecutor.cpp index 3663cdb0ec..de8e6b380f 100644 --- a/services/surfaceflinger/BackgroundExecutor.cpp +++ b/services/surfaceflinger/BackgroundExecutor.cpp @@ -32,7 +32,9 @@ BackgroundExecutor::BackgroundExecutor() : Singleton() { std::vector> tasks; { std::unique_lock lock(mMutex); - mWorkAvailableCv.wait(lock, [&]() { return mDone || !mTasks.empty(); }); + android::base::ScopedLockAssertion assumeLock(mMutex); + mWorkAvailableCv.wait(lock, + [&]() REQUIRES(mMutex) { return mDone || !mTasks.empty(); }); tasks = std::move(mTasks); mTasks.clear(); done = mDone; @@ -47,7 +49,7 @@ BackgroundExecutor::BackgroundExecutor() : Singleton() { BackgroundExecutor::~BackgroundExecutor() { { - std::unique_lock lock(mMutex); + std::scoped_lock lock(mMutex); mDone = true; mWorkAvailableCv.notify_all(); } @@ -57,7 +59,7 @@ BackgroundExecutor::~BackgroundExecutor() { } void BackgroundExecutor::execute(std::function task) { - std::unique_lock lock(mMutex); + std::scoped_lock lock(mMutex); mTasks.emplace_back(std::move(task)); mWorkAvailableCv.notify_all(); } diff --git a/services/surfaceflinger/BackgroundExecutor.h b/services/surfaceflinger/BackgroundExecutor.h index 6f6d305280..6db7dda7aa 100644 --- a/services/surfaceflinger/BackgroundExecutor.h +++ b/services/surfaceflinger/BackgroundExecutor.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include #include @@ -33,10 +34,10 @@ public: private: std::mutex mMutex; - std::condition_variable mWorkAvailableCv; + std::condition_variable mWorkAvailableCv GUARDED_BY(mMutex); + bool mDone GUARDED_BY(mMutex) = false; + std::vector> mTasks GUARDED_BY(mMutex); std::thread mThread; - bool mDone = false; - std::vector> mTasks; }; } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 93f8406319..27fc942915 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -93,6 +93,7 @@ #include #include +#include "BackgroundExecutor.h" #include "BufferLayer.h" #include "BufferQueueLayer.h" #include "BufferStateLayer.h" @@ -508,7 +509,7 @@ void SurfaceFlinger::binderDied(const wp&) { mBootFinished = false; // Sever the link to inputflinger since it's gone as well. - static_cast(mScheduler->schedule([=] { mInputFlinger = nullptr; })); + BackgroundExecutor::getInstance().execute([=] { mInputFlinger = nullptr; }); // restore initial conditions (default device unblank, etc) initializeDisplays(); @@ -719,13 +720,15 @@ void SurfaceFlinger::bootFinished() { sp input(defaultServiceManager()->getService(String16("inputflinger"))); - static_cast(mScheduler->schedule([=] { + BackgroundExecutor::getInstance().execute([=] { if (input == nullptr) { ALOGE("Failed to link to input service"); } else { mInputFlinger = interface_cast(input); } + }); + static_cast(mScheduler->schedule([=] { readPersistentProperties(); mPowerAdvisor.onBootFinished(); mBootStage = BootStage::FINISHED; @@ -3004,32 +3007,48 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { void SurfaceFlinger::updateInputFlinger() { ATRACE_CALL(); - if (!mInputFlinger) { - return; - } - + std::vector windowInfos; + std::vector displayInfos; + bool updateWindowInfo = false; if (mVisibleRegionsDirty || mInputInfoChanged) { mInputInfoChanged = false; - notifyWindowInfos(); - } else if (mInputWindowCommands.syncInputWindows) { - // If the caller requested to sync input windows, but there are no - // changes to input windows, notify immediately. - windowInfosReported(); + updateWindowInfo = true; + buildWindowInfos(windowInfos, displayInfos); } - - for (const auto& focusRequest : mInputWindowCommands.focusRequests) { - mInputFlinger->setFocusedWindow(focusRequest); + if (!updateWindowInfo && mInputWindowCommands.empty()) { + return; } + BackgroundExecutor::getInstance().execute([updateWindowInfo, + windowInfos = std::move(windowInfos), + displayInfos = std::move(displayInfos), + inputWindowCommands = + std::move(mInputWindowCommands), + this]() { + ATRACE_NAME("BackgroundExecutor::updateInputFlinger"); + if (!mInputFlinger) { + return; + } + if (updateWindowInfo) { + mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos, + inputWindowCommands.syncInputWindows); + } else if (inputWindowCommands.syncInputWindows) { + // If the caller requested to sync input windows, but there are no + // changes to input windows, notify immediately. + windowInfosReported(); + } + for (const auto& focusRequest : inputWindowCommands.focusRequests) { + mInputFlinger->setFocusedWindow(focusRequest); + } + }); + mInputWindowCommands.clear(); } -void SurfaceFlinger::notifyWindowInfos() { - std::vector windowInfos; - std::vector displayInfos; +void SurfaceFlinger::buildWindowInfos(std::vector& outWindowInfos, + std::vector& outDisplayInfos) { std::unordered_map> inputDisplayDetails; - for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { if (!display->receivesInput()) { continue; @@ -3043,7 +3062,7 @@ void SurfaceFlinger::notifyWindowInfos() { layerStackId); continue; } - displayInfos.emplace_back(info); + outDisplayInfos.emplace_back(info); } mDrawingState.traverseInReverseZOrder([&](Layer* layer) { @@ -3063,10 +3082,8 @@ void SurfaceFlinger::notifyWindowInfos() { layer->getDebugName(), layerStackId); } - windowInfos.push_back(layer->fillInputInfo(displayTransform, isSecure)); + outWindowInfos.push_back(layer->fillInputInfo(displayTransform, isSecure)); }); - mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos, - mInputWindowCommands.syncInputWindows); } void SurfaceFlinger::updateCursorAsync() { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6093be91f9..353f747ce5 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -689,7 +689,8 @@ private: void updateLayerGeometry(); void updateInputFlinger(); - void notifyWindowInfos(); + void buildWindowInfos(std::vector& outWindowInfos, + std::vector& outDisplayInfos); void commitInputWindowCommands() REQUIRES(mStateLock); void updateCursorAsync(); @@ -1289,6 +1290,7 @@ private: const float mInternalDisplayDensity; const float mEmulatedDisplayDensity; + // Should only be accessed by BackgroundExecutor thread. sp mInputFlinger; // Should only be accessed by the main thread. InputWindowCommands mInputWindowCommands; -- cgit v1.2.3-59-g8ed1b From 0589be587f54d3d568ae18c428f2acd8d8254d1b Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Fri, 19 Nov 2021 16:39:20 -0500 Subject: Fix memory leak in AHardwareBuffer_isSupported This function creates a new GraphicBuffer to call a single method on it. Wrap it in an sp<> so that it gets deleted when it's no longer necessary. Bug: NA Test: make and flash Change-Id: I443015d63245e49e8cf38847030c9da8142cbe50 --- libs/nativewindow/AHardwareBuffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index e2f32e374a..d429551045 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -370,7 +370,7 @@ int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* desc) { if (!AHardwareBuffer_isValidDescription(desc, /*log=*/false)) return 0; bool supported = false; - GraphicBuffer* gBuffer = new GraphicBuffer(); + sp gBuffer(new GraphicBuffer()); status_t err = gBuffer->isSupported(desc->width, desc->height, desc->format, desc->layers, desc->usage, &supported); -- cgit v1.2.3-59-g8ed1b From 492c85c613ac94495c567465ad82b147b4526fb3 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 19 Nov 2021 15:58:10 -0800 Subject: Introduce libshaders static library This library is for exposing system-only shader implementations in SkSL. Notably: libshaders depends on the vendor available libtonemap, but libtonemap is vendor available as it is a single source of truth for tonemap operations, whereas libshaders is not meant to be shared with the vendor partition. Rather, the intent is to allow for sharing of SkSL between librenderengine and libhwui. Bug: 200309590 Ignore-AOSP-First: Introduces internal-only library Test: builds Change-Id: I611b79eb3addd15528f0cdb70e9f2f3d62473ec1 --- libs/renderengine/Android.bp | 1 + libs/renderengine/benchmark/Android.bp | 1 + libs/renderengine/skia/SkiaGLRenderEngine.cpp | 6 +- libs/renderengine/skia/SkiaGLRenderEngine.h | 3 +- libs/renderengine/skia/filters/LinearEffect.cpp | 320 +-------------------- libs/renderengine/skia/filters/LinearEffect.h | 59 +--- libs/renderengine/tests/Android.bp | 1 + libs/shaders/Android.bp | 44 +++ libs/shaders/OWNERS | 4 + libs/shaders/include/shaders/shaders.h | 105 +++++++ libs/shaders/shaders.cpp | 361 ++++++++++++++++++++++++ services/surfaceflinger/Android.bp | 1 + 12 files changed, 535 insertions(+), 371 deletions(-) create mode 100644 libs/shaders/Android.bp create mode 100644 libs/shaders/OWNERS create mode 100644 libs/shaders/include/shaders/shaders.h create mode 100644 libs/shaders/shaders.cpp diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index ecfaef8928..07c5dd8a82 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -42,6 +42,7 @@ cc_defaults { ], static_libs: [ + "libshaders", "libtonemap", ], local_include_dirs: ["include"], diff --git a/libs/renderengine/benchmark/Android.bp b/libs/renderengine/benchmark/Android.bp index baa50544b7..471159f390 100644 --- a/libs/renderengine/benchmark/Android.bp +++ b/libs/renderengine/benchmark/Android.bp @@ -35,6 +35,7 @@ cc_benchmark { ], static_libs: [ "librenderengine", + "libshaders", "libtonemap", ], cflags: [ diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index 21d56032c2..376e279473 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -636,9 +636,9 @@ sk_sp SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp sh const ui::Dataspace outputDataspace = mUseColorManagement ? display.outputDataspace : ui::Dataspace::V0_SRGB_LINEAR; - LinearEffect effect = LinearEffect{.inputDataspace = inputDataspace, - .outputDataspace = outputDataspace, - .undoPremultipliedAlpha = undoPremultipliedAlpha}; + auto effect = shaders::LinearEffect{.inputDataspace = inputDataspace, + .outputDataspace = outputDataspace, + .undoPremultipliedAlpha = undoPremultipliedAlpha}; auto effectIter = mRuntimeEffects.find(effect); sk_sp runtimeEffect = nullptr; diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index 74ce6513e9..53792f9731 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -133,7 +133,8 @@ private: // Cache of GL textures that we'll store per GraphicBuffer ID, shared between GPU contexts. std::unordered_map> mTextureCache GUARDED_BY(mRenderingMutex); - std::unordered_map, LinearEffectHasher> mRuntimeEffects; + std::unordered_map, shaders::LinearEffectHasher> + mRuntimeEffects; AutoBackendTexture::CleanupManager mTextureCleanupMgr GUARDED_BY(mRenderingMutex); StretchShaderFactory mStretchShaderFactory; diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp index b43a3aa5ce..36305aeea8 100644 --- a/libs/renderengine/skia/filters/LinearEffect.cpp +++ b/libs/renderengine/skia/filters/LinearEffect.cpp @@ -19,303 +19,19 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include -#include +#include +#include #include -#include - -#include "log/log.h" -#include "math/mat4.h" -#include "system/graphics-base-v1.0.h" -#include "ui/ColorSpace.h" +#include namespace android { namespace renderengine { namespace skia { -static aidl::android::hardware::graphics::common::Dataspace toAidlDataspace( - ui::Dataspace dataspace) { - return static_cast(dataspace); -} - -static void generateEOTF(ui::Dataspace dataspace, SkString& shader) { - switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) { - case HAL_DATASPACE_TRANSFER_ST2084: - shader.append(R"( - - float3 EOTF(float3 color) { - float m1 = (2610.0 / 4096.0) / 4.0; - float m2 = (2523.0 / 4096.0) * 128.0; - float c1 = (3424.0 / 4096.0); - float c2 = (2413.0 / 4096.0) * 32.0; - float c3 = (2392.0 / 4096.0) * 32.0; - - float3 tmp = pow(clamp(color, 0.0, 1.0), 1.0 / float3(m2)); - tmp = max(tmp - c1, 0.0) / (c2 - c3 * tmp); - return pow(tmp, 1.0 / float3(m1)); - } - )"); - break; - case HAL_DATASPACE_TRANSFER_HLG: - shader.append(R"( - float EOTF_channel(float channel) { - const float a = 0.17883277; - const float b = 0.28466892; - const float c = 0.55991073; - return channel <= 0.5 ? channel * channel / 3.0 : - (exp((channel - c) / a) + b) / 12.0; - } - - float3 EOTF(float3 color) { - return float3(EOTF_channel(color.r), EOTF_channel(color.g), - EOTF_channel(color.b)); - } - )"); - break; - case HAL_DATASPACE_TRANSFER_LINEAR: - shader.append(R"( - float3 EOTF(float3 color) { - return color; - } - )"); - break; - case HAL_DATASPACE_TRANSFER_SRGB: - default: - shader.append(R"( - - float EOTF_sRGB(float srgb) { - return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4); - } - - float3 EOTF_sRGB(float3 srgb) { - return float3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b)); - } - - float3 EOTF(float3 srgb) { - return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb)); - } - )"); - break; - } -} - -static void generateXYZTransforms(SkString& shader) { - shader.append(R"( - uniform float4x4 in_rgbToXyz; - uniform float4x4 in_xyzToRgb; - float3 ToXYZ(float3 rgb) { - return (in_rgbToXyz * float4(rgb, 1.0)).rgb; - } - - float3 ToRGB(float3 xyz) { - return clamp((in_xyzToRgb * float4(xyz, 1.0)).rgb, 0.0, 1.0); - } - )"); -} - -// Conversion from relative light to absolute light (maps from [0, 1] to [0, maxNits]) -static void generateLuminanceScalesForOOTF(ui::Dataspace inputDataspace, - ui::Dataspace outputDataspace, SkString& shader) { - switch (inputDataspace & HAL_DATASPACE_TRANSFER_MASK) { - case HAL_DATASPACE_TRANSFER_ST2084: - shader.append(R"( - float3 ScaleLuminance(float3 xyz) { - return xyz * 10000.0; - } - )"); - break; - case HAL_DATASPACE_TRANSFER_HLG: - shader.append(R"( - float3 ScaleLuminance(float3 xyz) { - return xyz * 1000.0 * pow(xyz.y, 0.2); - } - )"); - break; - default: - switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) { - case HAL_DATASPACE_TRANSFER_ST2084: - case HAL_DATASPACE_TRANSFER_HLG: - // SDR -> HDR tonemap - shader.append(R"( - float3 ScaleLuminance(float3 xyz) { - return xyz * in_libtonemap_inputMaxLuminance; - } - )"); - break; - default: - // Input and output are both SDR, so no tone-mapping is expected so - // no-op the luminance normalization. - shader.append(R"( - float3 ScaleLuminance(float3 xyz) { - return xyz * in_libtonemap_displayMaxLuminance; - } - )"); - break; - } - } -} - -// Normalizes from absolute light back to relative light (maps from [0, maxNits] back to [0, 1]) -static void generateLuminanceNormalizationForOOTF(ui::Dataspace outputDataspace, SkString& shader) { - switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) { - case HAL_DATASPACE_TRANSFER_ST2084: - shader.append(R"( - float3 NormalizeLuminance(float3 xyz) { - return xyz / 10000.0; - } - )"); - break; - case HAL_DATASPACE_TRANSFER_HLG: - shader.append(R"( - float3 NormalizeLuminance(float3 xyz) { - return xyz / 1000.0 * pow(xyz.y / 1000.0, -0.2 / 1.2); - } - )"); - break; - default: - shader.append(R"( - float3 NormalizeLuminance(float3 xyz) { - return xyz / in_libtonemap_displayMaxLuminance; - } - )"); - break; - } -} - -static void generateOOTF(ui::Dataspace inputDataspace, ui::Dataspace outputDataspace, - SkString& shader) { - shader.append(tonemap::getToneMapper() - ->generateTonemapGainShaderSkSL(toAidlDataspace(inputDataspace), - toAidlDataspace(outputDataspace)) - .c_str()); - - generateLuminanceScalesForOOTF(inputDataspace, outputDataspace, shader); - generateLuminanceNormalizationForOOTF(outputDataspace, shader); - - shader.append(R"( - float3 OOTF(float3 linearRGB, float3 xyz) { - float3 scaledLinearRGB = ScaleLuminance(linearRGB); - float3 scaledXYZ = ScaleLuminance(xyz); - - float gain = libtonemap_LookupTonemapGain(scaledLinearRGB, scaledXYZ); - - return NormalizeLuminance(scaledXYZ * gain); - } - )"); -} - -static void generateOETF(ui::Dataspace dataspace, SkString& shader) { - switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) { - case HAL_DATASPACE_TRANSFER_ST2084: - shader.append(R"( - - float3 OETF(float3 xyz) { - float m1 = (2610.0 / 4096.0) / 4.0; - float m2 = (2523.0 / 4096.0) * 128.0; - float c1 = (3424.0 / 4096.0); - float c2 = (2413.0 / 4096.0) * 32.0; - float c3 = (2392.0 / 4096.0) * 32.0; - - float3 tmp = pow(xyz, float3(m1)); - tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp); - return pow(tmp, float3(m2)); - } - )"); - break; - case HAL_DATASPACE_TRANSFER_HLG: - shader.append(R"( - float OETF_channel(float channel) { - const float a = 0.17883277; - const float b = 0.28466892; - const float c = 0.55991073; - return channel <= 1.0 / 12.0 ? sqrt(3.0 * channel) : - a * log(12.0 * channel - b) + c; - } - - float3 OETF(float3 linear) { - return float3(OETF_channel(linear.r), OETF_channel(linear.g), - OETF_channel(linear.b)); - } - )"); - break; - case HAL_DATASPACE_TRANSFER_LINEAR: - shader.append(R"( - float3 OETF(float3 linear) { - return linear; - } - )"); - break; - case HAL_DATASPACE_TRANSFER_SRGB: - default: - shader.append(R"( - float OETF_sRGB(float linear) { - return linear <= 0.0031308 ? - linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055; - } - - float3 OETF_sRGB(float3 linear) { - return float3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b)); - } - - float3 OETF(float3 linear) { - return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb)); - } - )"); - break; - } -} - -static void generateEffectiveOOTF(bool undoPremultipliedAlpha, SkString& shader) { - shader.append(R"( - uniform shader child; - half4 main(float2 xy) { - float4 c = float4(child.eval(xy)); - )"); - if (undoPremultipliedAlpha) { - shader.append(R"( - c.rgb = c.rgb / (c.a + 0.0019); - )"); - } - shader.append(R"( - float3 linearRGB = EOTF(c.rgb); - float3 xyz = ToXYZ(linearRGB); - c.rgb = OETF(ToRGB(OOTF(linearRGB, xyz))); - )"); - if (undoPremultipliedAlpha) { - shader.append(R"( - c.rgb = c.rgb * (c.a + 0.0019); - )"); - } - shader.append(R"( - return c; - } - )"); -} -static ColorSpace toColorSpace(ui::Dataspace dataspace) { - switch (dataspace & HAL_DATASPACE_STANDARD_MASK) { - case HAL_DATASPACE_STANDARD_BT709: - return ColorSpace::sRGB(); - break; - case HAL_DATASPACE_STANDARD_DCI_P3: - return ColorSpace::DisplayP3(); - break; - case HAL_DATASPACE_STANDARD_BT2020: - return ColorSpace::BT2020(); - break; - default: - return ColorSpace::sRGB(); - break; - } -} - -sk_sp buildRuntimeEffect(const LinearEffect& linearEffect) { +sk_sp buildRuntimeEffect(const shaders::LinearEffect& linearEffect) { ATRACE_CALL(); - SkString shaderString; - generateEOTF(linearEffect.inputDataspace, shaderString); - generateXYZTransforms(shaderString); - generateOOTF(linearEffect.inputDataspace, linearEffect.outputDataspace, shaderString); - generateOETF(linearEffect.outputDataspace, shaderString); - generateEffectiveOOTF(linearEffect.undoPremultipliedAlpha, shaderString); + SkString shaderString = SkString(shaders::buildLinearEffectSkSL(linearEffect)); auto [shader, error] = SkRuntimeEffect::MakeForShader(shaderString); if (!shader) { @@ -324,7 +40,8 @@ sk_sp buildRuntimeEffect(const LinearEffect& linearEffect) { return shader; } -sk_sp createLinearEffectShader(sk_sp shader, const LinearEffect& linearEffect, +sk_sp createLinearEffectShader(sk_sp shader, + const shaders::LinearEffect& linearEffect, sk_sp runtimeEffect, const mat4& colorTransform, float maxDisplayLuminance, float maxLuminance) { @@ -333,27 +50,8 @@ sk_sp createLinearEffectShader(sk_sp shader, const LinearEff effectBuilder.child("child") = shader; - if (linearEffect.inputDataspace == linearEffect.outputDataspace) { - effectBuilder.uniform("in_rgbToXyz") = mat4(); - effectBuilder.uniform("in_xyzToRgb") = colorTransform; - } else { - ColorSpace inputColorSpace = toColorSpace(linearEffect.inputDataspace); - ColorSpace outputColorSpace = toColorSpace(linearEffect.outputDataspace); - - effectBuilder.uniform("in_rgbToXyz") = mat4(inputColorSpace.getRGBtoXYZ()); - effectBuilder.uniform("in_xyzToRgb") = - colorTransform * mat4(outputColorSpace.getXYZtoRGB()); - } - - tonemap::Metadata metadata{.displayMaxLuminance = maxDisplayLuminance, - // If the input luminance is unknown, use display luminance (aka, - // no-op any luminance changes) - // This will be the case for eg screenshots in addition to - // uncalibrated displays - .contentMaxLuminance = - maxLuminance > 0 ? maxLuminance : maxDisplayLuminance}; - - const auto uniforms = tonemap::getToneMapper()->generateShaderSkSLUniforms(metadata); + const auto uniforms = shaders::buildLinearEffectUniforms(linearEffect, colorTransform, + maxDisplayLuminance, maxLuminance); for (const auto& uniform : uniforms) { effectBuilder.uniform(uniform.name.c_str()).set(uniform.value.data(), uniform.value.size()); diff --git a/libs/renderengine/skia/filters/LinearEffect.h b/libs/renderengine/skia/filters/LinearEffect.h index 14a3b61ede..8eb6670150 100644 --- a/libs/renderengine/skia/filters/LinearEffect.h +++ b/libs/renderengine/skia/filters/LinearEffect.h @@ -20,6 +20,7 @@ #include +#include #include "SkRuntimeEffect.h" #include "SkShader.h" #include "ui/GraphicTypes.h" @@ -28,61 +29,7 @@ namespace android { namespace renderengine { namespace skia { -/** - * Arguments for creating an effect that applies color transformations in linear XYZ space. - * A linear effect is decomposed into the following steps when operating on an image: - * 1. Electrical-Optical Transfer Function (EOTF) maps the input RGB signal into the intended - * relative display brightness of the scene in nits for each RGB channel - * 2. Transformation matrix from linear RGB brightness to linear XYZ, to operate on display - * luminance. - * 3. Opto-Optical Transfer Function (OOTF) applies a "rendering intent". This can include tone - * mapping to display SDR content alongside HDR content, or any number of subjective transformations - * 4. Transformation matrix from linear XYZ back to linear RGB brightness. - * 5. Opto-Electronic Transfer Function (OETF) maps the display brightness of the scene back to - * output RGB colors. - * - * For further reading, consult the recommendation in ITU-R BT.2390-4: - * https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2390-4-2018-PDF-E.pdf - * - * Skia normally attempts to do its own simple tone mapping, i.e., the working color space is - * intended to be the output surface. However, Skia does not support complex tone mapping such as - * polynomial interpolation. As such, this filter assumes that tone mapping has not yet been applied - * to the source colors. so that the tone mapping process is only applied once by this effect. Tone - * mapping is applied when presenting HDR content (content with HLG or PQ transfer functions) - * alongside other content, whereby maximum input luminance is mapped to maximum output luminance - * and intermediate values are interpolated. - */ -struct LinearEffect { - // Input dataspace of the source colors. - const ui::Dataspace inputDataspace = ui::Dataspace::SRGB; - - // Working dataspace for the output surface, for conversion from linear space. - const ui::Dataspace outputDataspace = ui::Dataspace::SRGB; - - // Sets whether alpha premultiplication must be undone. - // This is required if the source colors use premultiplied alpha and is not opaque. - const bool undoPremultipliedAlpha = false; -}; - -static inline bool operator==(const LinearEffect& lhs, const LinearEffect& rhs) { - return lhs.inputDataspace == rhs.inputDataspace && lhs.outputDataspace == rhs.outputDataspace && - lhs.undoPremultipliedAlpha == rhs.undoPremultipliedAlpha; -} - -struct LinearEffectHasher { - // Inspired by art/runtime/class_linker.cc - // Also this is what boost:hash_combine does - static size_t HashCombine(size_t seed, size_t val) { - return seed ^ (val + 0x9e3779b9 + (seed << 6) + (seed >> 2)); - } - size_t operator()(const LinearEffect& le) const { - size_t result = std::hash{}(le.inputDataspace); - result = HashCombine(result, std::hash{}(le.outputDataspace)); - return HashCombine(result, std::hash{}(le.undoPremultipliedAlpha)); - } -}; - -sk_sp buildRuntimeEffect(const LinearEffect& linearEffect); +sk_sp buildRuntimeEffect(const shaders::LinearEffect& linearEffect); // Generates a shader resulting from applying the a linear effect created from // LinearEffectArgs::buildEffect to an inputShader. @@ -93,7 +40,7 @@ sk_sp buildRuntimeEffect(const LinearEffect& linearEffect); // * The max luminance is provided as the max luminance for the buffer, either from the SMPTE 2086 // or as the max light level from the CTA 861.3 standard. sk_sp createLinearEffectShader(sk_sp inputShader, - const LinearEffect& linearEffect, + const shaders::LinearEffect& linearEffect, sk_sp runtimeEffect, const mat4& colorTransform, float maxDisplayLuminance, float maxLuminance); diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp index 52b6c8ff72..a426850350 100644 --- a/libs/renderengine/tests/Android.bp +++ b/libs/renderengine/tests/Android.bp @@ -39,6 +39,7 @@ cc_test { "libgmock", "librenderengine", "librenderengine_mocks", + "libshaders", "libtonemap", ], diff --git a/libs/shaders/Android.bp b/libs/shaders/Android.bp new file mode 100644 index 0000000000..390b22821e --- /dev/null +++ b/libs/shaders/Android.bp @@ -0,0 +1,44 @@ +// Copyright 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + +cc_library_static { + name: "libshaders", + + export_include_dirs: ["include"], + local_include_dirs: ["include"], + + shared_libs: [ + "android.hardware.graphics.common-V3-ndk", + "android.hardware.graphics.common@1.2", + ], + + static_libs: [ + "libmath", + "libtonemap", + "libui-types", + ], + + srcs: [ + "shaders.cpp", + ], +} diff --git a/libs/shaders/OWNERS b/libs/shaders/OWNERS new file mode 100644 index 0000000000..6d91da3bd2 --- /dev/null +++ b/libs/shaders/OWNERS @@ -0,0 +1,4 @@ +alecmouri@google.com +jreck@google.com +sallyqi@google.com +scroggo@google.com \ No newline at end of file diff --git a/libs/shaders/include/shaders/shaders.h b/libs/shaders/include/shaders/shaders.h new file mode 100644 index 0000000000..712a27a3eb --- /dev/null +++ b/libs/shaders/include/shaders/shaders.h @@ -0,0 +1,105 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +namespace android::shaders { + +/** + * Arguments for creating an effect that applies color transformations in linear XYZ space. + * A linear effect is decomposed into the following steps when operating on an image: + * 1. Electrical-Optical Transfer Function (EOTF) maps the input RGB signal into the intended + * relative display brightness of the scene in nits for each RGB channel + * 2. Transformation matrix from linear RGB brightness to linear XYZ, to operate on display + * luminance. + * 3. Opto-Optical Transfer Function (OOTF) applies a "rendering intent". This can include tone + * mapping to display SDR content alongside HDR content, or any number of subjective transformations + * 4. Transformation matrix from linear XYZ back to linear RGB brightness. + * 5. Opto-Electronic Transfer Function (OETF) maps the display brightness of the scene back to + * output RGB colors. + * + * For further reading, consult the recommendation in ITU-R BT.2390-4: + * https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2390-4-2018-PDF-E.pdf + * + * Skia normally attempts to do its own simple tone mapping, i.e., the working color space is + * intended to be the output surface. However, Skia does not support complex tone mapping such as + * polynomial interpolation. As such, this filter assumes that tone mapping has not yet been applied + * to the source colors. so that the tone mapping process is only applied once by this effect. Tone + * mapping is applied when presenting HDR content (content with HLG or PQ transfer functions) + * alongside other content, whereby maximum input luminance is mapped to maximum output luminance + * and intermediate values are interpolated. + */ +struct LinearEffect { + // Input dataspace of the source colors. + const ui::Dataspace inputDataspace = ui::Dataspace::SRGB; + + // Working dataspace for the output surface, for conversion from linear space. + const ui::Dataspace outputDataspace = ui::Dataspace::SRGB; + + // Sets whether alpha premultiplication must be undone. + // This is required if the source colors use premultiplied alpha and is not opaque. + const bool undoPremultipliedAlpha = false; + + // "Fake" dataspace of the source colors. This is used for applying an EOTF to compute linear + // RGB. This is used when Skia is expected to color manage the input image based on the + // dataspace of the provided source image and destination surface. SkRuntimeEffects use the + // destination color space as the working color space. RenderEngine deliberately sets the color + // space for input images and destination surfaces to be the same whenever LinearEffects are + // expected to be used so that color-management is controlled by RenderEngine, but other users + // of a LinearEffect may not be able to control the color space of the images and surfaces. So + // fakeInputDataspace is used to essentially masquerade the input dataspace to be the output + // dataspace for correct conversion to linear colors. + ui::Dataspace fakeInputDataspace = ui::Dataspace::UNKNOWN; +}; + +static inline bool operator==(const LinearEffect& lhs, const LinearEffect& rhs) { + return lhs.inputDataspace == rhs.inputDataspace && lhs.outputDataspace == rhs.outputDataspace && + lhs.undoPremultipliedAlpha == rhs.undoPremultipliedAlpha && + lhs.fakeInputDataspace == rhs.fakeInputDataspace; +} + +struct LinearEffectHasher { + // Inspired by art/runtime/class_linker.cc + // Also this is what boost:hash_combine does + static size_t HashCombine(size_t seed, size_t val) { + return seed ^ (val + 0x9e3779b9 + (seed << 6) + (seed >> 2)); + } + size_t operator()(const LinearEffect& le) const { + size_t result = std::hash{}(le.inputDataspace); + result = HashCombine(result, std::hash{}(le.outputDataspace)); + result = HashCombine(result, std::hash{}(le.undoPremultipliedAlpha)); + return HashCombine(result, std::hash{}(le.fakeInputDataspace)); + } +}; + +// Generates a shader string that applies color transforms in linear space. +// Typical use-cases supported: +// 1. Apply tone-mapping +// 2. Apply color transform matrices in linear space +std::string buildLinearEffectSkSL(const LinearEffect& linearEffect); + +// Generates a list of uniforms to set on the LinearEffect shader above. +std::vector buildLinearEffectUniforms(const LinearEffect& linearEffect, + const mat4& colorTransform, + float maxDisplayLuminance, + float maxLuminance); + +} // namespace android::shaders diff --git a/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp new file mode 100644 index 0000000000..ee2d4a46a5 --- /dev/null +++ b/libs/shaders/shaders.cpp @@ -0,0 +1,361 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include + +#include +#include +#include + +namespace android::shaders { + +static aidl::android::hardware::graphics::common::Dataspace toAidlDataspace( + ui::Dataspace dataspace) { + return static_cast(dataspace); +} + +static void generateEOTF(ui::Dataspace dataspace, std::string& shader) { + switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) { + case HAL_DATASPACE_TRANSFER_ST2084: + shader.append(R"( + + float3 EOTF(float3 color) { + float m1 = (2610.0 / 4096.0) / 4.0; + float m2 = (2523.0 / 4096.0) * 128.0; + float c1 = (3424.0 / 4096.0); + float c2 = (2413.0 / 4096.0) * 32.0; + float c3 = (2392.0 / 4096.0) * 32.0; + + float3 tmp = pow(clamp(color, 0.0, 1.0), 1.0 / float3(m2)); + tmp = max(tmp - c1, 0.0) / (c2 - c3 * tmp); + return pow(tmp, 1.0 / float3(m1)); + } + )"); + break; + case HAL_DATASPACE_TRANSFER_HLG: + shader.append(R"( + float EOTF_channel(float channel) { + const float a = 0.17883277; + const float b = 0.28466892; + const float c = 0.55991073; + return channel <= 0.5 ? channel * channel / 3.0 : + (exp((channel - c) / a) + b) / 12.0; + } + + float3 EOTF(float3 color) { + return float3(EOTF_channel(color.r), EOTF_channel(color.g), + EOTF_channel(color.b)); + } + )"); + break; + case HAL_DATASPACE_TRANSFER_LINEAR: + shader.append(R"( + float3 EOTF(float3 color) { + return color; + } + )"); + break; + case HAL_DATASPACE_TRANSFER_SRGB: + default: + shader.append(R"( + + float EOTF_sRGB(float srgb) { + return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4); + } + + float3 EOTF_sRGB(float3 srgb) { + return float3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b)); + } + + float3 EOTF(float3 srgb) { + return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb)); + } + )"); + break; + } +} + +static void generateXYZTransforms(std::string& shader) { + shader.append(R"( + uniform float4x4 in_rgbToXyz; + uniform float4x4 in_xyzToRgb; + float3 ToXYZ(float3 rgb) { + return (in_rgbToXyz * float4(rgb, 1.0)).rgb; + } + + float3 ToRGB(float3 xyz) { + return clamp((in_xyzToRgb * float4(xyz, 1.0)).rgb, 0.0, 1.0); + } + )"); +} + +// Conversion from relative light to absolute light (maps from [0, 1] to [0, maxNits]) +static void generateLuminanceScalesForOOTF(ui::Dataspace inputDataspace, + ui::Dataspace outputDataspace, std::string& shader) { + switch (inputDataspace & HAL_DATASPACE_TRANSFER_MASK) { + case HAL_DATASPACE_TRANSFER_ST2084: + shader.append(R"( + float3 ScaleLuminance(float3 xyz) { + return xyz * 10000.0; + } + )"); + break; + case HAL_DATASPACE_TRANSFER_HLG: + shader.append(R"( + float3 ScaleLuminance(float3 xyz) { + return xyz * 1000.0 * pow(xyz.y, 0.2); + } + )"); + break; + default: + switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) { + case HAL_DATASPACE_TRANSFER_ST2084: + case HAL_DATASPACE_TRANSFER_HLG: + // SDR -> HDR tonemap + shader.append(R"( + float3 ScaleLuminance(float3 xyz) { + return xyz * in_libtonemap_inputMaxLuminance; + } + )"); + break; + default: + // Input and output are both SDR, so no tone-mapping is expected so + // no-op the luminance normalization. + shader.append(R"( + float3 ScaleLuminance(float3 xyz) { + return xyz * in_libtonemap_displayMaxLuminance; + } + )"); + break; + } + } +} + +// Normalizes from absolute light back to relative light (maps from [0, maxNits] back to [0, 1]) +static void generateLuminanceNormalizationForOOTF(ui::Dataspace outputDataspace, + std::string& shader) { + switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) { + case HAL_DATASPACE_TRANSFER_ST2084: + shader.append(R"( + float3 NormalizeLuminance(float3 xyz) { + return xyz / 10000.0; + } + )"); + break; + case HAL_DATASPACE_TRANSFER_HLG: + shader.append(R"( + float3 NormalizeLuminance(float3 xyz) { + return xyz / 1000.0 * pow(xyz.y / 1000.0, -0.2 / 1.2); + } + )"); + break; + default: + shader.append(R"( + float3 NormalizeLuminance(float3 xyz) { + return xyz / in_libtonemap_displayMaxLuminance; + } + )"); + break; + } +} + +static void generateOOTF(ui::Dataspace inputDataspace, ui::Dataspace outputDataspace, + std::string& shader) { + shader.append(tonemap::getToneMapper() + ->generateTonemapGainShaderSkSL(toAidlDataspace(inputDataspace), + toAidlDataspace(outputDataspace)) + .c_str()); + + generateLuminanceScalesForOOTF(inputDataspace, outputDataspace, shader); + generateLuminanceNormalizationForOOTF(outputDataspace, shader); + + shader.append(R"( + float3 OOTF(float3 linearRGB, float3 xyz) { + float3 scaledLinearRGB = ScaleLuminance(linearRGB); + float3 scaledXYZ = ScaleLuminance(xyz); + + float gain = libtonemap_LookupTonemapGain(scaledLinearRGB, scaledXYZ); + + return NormalizeLuminance(scaledXYZ * gain); + } + )"); +} + +static void generateOETF(ui::Dataspace dataspace, std::string& shader) { + switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) { + case HAL_DATASPACE_TRANSFER_ST2084: + shader.append(R"( + + float3 OETF(float3 xyz) { + float m1 = (2610.0 / 4096.0) / 4.0; + float m2 = (2523.0 / 4096.0) * 128.0; + float c1 = (3424.0 / 4096.0); + float c2 = (2413.0 / 4096.0) * 32.0; + float c3 = (2392.0 / 4096.0) * 32.0; + + float3 tmp = pow(xyz, float3(m1)); + tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp); + return pow(tmp, float3(m2)); + } + )"); + break; + case HAL_DATASPACE_TRANSFER_HLG: + shader.append(R"( + float OETF_channel(float channel) { + const float a = 0.17883277; + const float b = 0.28466892; + const float c = 0.55991073; + return channel <= 1.0 / 12.0 ? sqrt(3.0 * channel) : + a * log(12.0 * channel - b) + c; + } + + float3 OETF(float3 linear) { + return float3(OETF_channel(linear.r), OETF_channel(linear.g), + OETF_channel(linear.b)); + } + )"); + break; + case HAL_DATASPACE_TRANSFER_LINEAR: + shader.append(R"( + float3 OETF(float3 linear) { + return linear; + } + )"); + break; + case HAL_DATASPACE_TRANSFER_SRGB: + default: + shader.append(R"( + float OETF_sRGB(float linear) { + return linear <= 0.0031308 ? + linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055; + } + + float3 OETF_sRGB(float3 linear) { + return float3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b)); + } + + float3 OETF(float3 linear) { + return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb)); + } + )"); + break; + } +} + +static void generateEffectiveOOTF(bool undoPremultipliedAlpha, std::string& shader) { + shader.append(R"( + uniform shader child; + half4 main(float2 xy) { + float4 c = float4(child.eval(xy)); + )"); + if (undoPremultipliedAlpha) { + shader.append(R"( + c.rgb = c.rgb / (c.a + 0.0019); + )"); + } + shader.append(R"( + float3 linearRGB = EOTF(c.rgb); + float3 xyz = ToXYZ(linearRGB); + c.rgb = OETF(ToRGB(OOTF(linearRGB, xyz))); + )"); + if (undoPremultipliedAlpha) { + shader.append(R"( + c.rgb = c.rgb * (c.a + 0.0019); + )"); + } + shader.append(R"( + return c; + } + )"); +} +static ColorSpace toColorSpace(ui::Dataspace dataspace) { + switch (dataspace & HAL_DATASPACE_STANDARD_MASK) { + case HAL_DATASPACE_STANDARD_BT709: + return ColorSpace::sRGB(); + break; + case HAL_DATASPACE_STANDARD_DCI_P3: + return ColorSpace::DisplayP3(); + break; + case HAL_DATASPACE_STANDARD_BT2020: + return ColorSpace::BT2020(); + break; + default: + return ColorSpace::sRGB(); + break; + } +} + +std::string buildLinearEffectSkSL(const LinearEffect& linearEffect) { + std::string shaderString; + generateEOTF(linearEffect.fakeInputDataspace == ui::Dataspace::UNKNOWN + ? linearEffect.inputDataspace + : linearEffect.fakeInputDataspace, + shaderString); + generateXYZTransforms(shaderString); + generateOOTF(linearEffect.inputDataspace, linearEffect.outputDataspace, shaderString); + generateOETF(linearEffect.outputDataspace, shaderString); + generateEffectiveOOTF(linearEffect.undoPremultipliedAlpha, shaderString); + return shaderString; +} + +template ::value, bool> = true> +std::vector buildUniformValue(T value) { + std::vector result; + result.resize(sizeof(value)); + std::memcpy(result.data(), &value, sizeof(value)); + return result; +} + +// Generates a list of uniforms to set on the LinearEffect shader above. +std::vector buildLinearEffectUniforms(const LinearEffect& linearEffect, + const mat4& colorTransform, + float maxDisplayLuminance, + float maxLuminance) { + std::vector uniforms; + if (linearEffect.inputDataspace == linearEffect.outputDataspace) { + uniforms.push_back({.name = "in_rgbToXyz", .value = buildUniformValue(mat4())}); + uniforms.push_back( + {.name = "in_xyzToRgb", .value = buildUniformValue(colorTransform)}); + } else { + ColorSpace inputColorSpace = toColorSpace(linearEffect.inputDataspace); + ColorSpace outputColorSpace = toColorSpace(linearEffect.outputDataspace); + uniforms.push_back({.name = "in_rgbToXyz", + .value = buildUniformValue(mat4(inputColorSpace.getRGBtoXYZ()))}); + uniforms.push_back({.name = "in_xyzToRgb", + .value = buildUniformValue( + colorTransform * mat4(outputColorSpace.getXYZtoRGB()))}); + } + + tonemap::Metadata metadata{.displayMaxLuminance = maxDisplayLuminance, + // If the input luminance is unknown, use display luminance (aka, + // no-op any luminance changes) + // This will be the case for eg screenshots in addition to + // uncalibrated displays + .contentMaxLuminance = + maxLuminance > 0 ? maxLuminance : maxDisplayLuminance}; + + for (const auto uniform : tonemap::getToneMapper()->generateShaderSkSLUniforms(metadata)) { + uniforms.push_back(uniform); + } + + return uniforms; +} + +} // namespace android::shaders \ No newline at end of file diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index c453d62e6e..f16cd63646 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -80,6 +80,7 @@ cc_defaults { "librenderengine", "libscheduler", "libserviceutils", + "libshaders", "libtonemap", "libtrace_proto", ], -- cgit v1.2.3-59-g8ed1b From 78fc89a1f563fadde46c8955fd42115dd8cbf9d8 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Sun, 21 Nov 2021 16:59:30 -0800 Subject: Plumb HDR metadata through ASurfaceTexture This is just used for hwui's usage - HDR metadata on SurfaceTexture is not publicly exposed. Bug: 200309590 Test: builds, boots Change-Id: I373e50ee2d2000cb46c6a73d01e58b965c168311 --- .../include/surfacetexture/ImageConsumer.h | 3 ++- .../include/surfacetexture/SurfaceTexture.h | 4 ++-- .../include/surfacetexture/surface_texture_platform.h | 14 +++++++------- libs/nativedisplay/surfacetexture/ImageConsumer.cpp | 4 +++- libs/nativedisplay/surfacetexture/SurfaceTexture.cpp | 5 +++-- libs/nativedisplay/surfacetexture/surface_texture.cpp | 19 +++++++++++-------- 6 files changed, 28 insertions(+), 21 deletions(-) diff --git a/libs/nativedisplay/include/surfacetexture/ImageConsumer.h b/libs/nativedisplay/include/surfacetexture/ImageConsumer.h index 35ae3d2144..6fd4b8fff4 100644 --- a/libs/nativedisplay/include/surfacetexture/ImageConsumer.h +++ b/libs/nativedisplay/include/surfacetexture/ImageConsumer.h @@ -42,7 +42,8 @@ public: typedef status_t (*SurfaceTexture_fenceWait)(int fence, void* fencePassThroughHandle); sp dequeueBuffer(int* outSlotid, android_dataspace* outDataspace, - bool* outQueueEmpty, SurfaceTexture& cb, + HdrMetadata* outHdrMetadata, bool* outQueueEmpty, + SurfaceTexture& cb, SurfaceTexture_createReleaseFence createFence, SurfaceTexture_fenceWait fenceWait, void* fencePassThroughHandle); diff --git a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h index bac44c978a..0f119f3fc1 100644 --- a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h +++ b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h @@ -272,8 +272,8 @@ public: status_t attachToContext(uint32_t tex); sp dequeueBuffer(int* outSlotid, android_dataspace* outDataspace, - float* outTransformMatrix, uint32_t* outTransform, - bool* outQueueEmpty, + HdrMetadata* outHdrMetadata, float* outTransformMatrix, + uint32_t* outTransform, bool* outQueueEmpty, SurfaceTexture_createReleaseFence createFence, SurfaceTexture_fenceWait fenceWait, void* fencePassThroughHandle, ARect* currentCrop); diff --git a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h index e85009c206..2987f3a87a 100644 --- a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h +++ b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -82,13 +83,12 @@ typedef int (*ASurfaceTexture_fenceWait)(int fence, void* fencePassThroughHandle * The caller gets ownership of the buffer and need to release it with * AHardwareBuffer_release. */ -AHardwareBuffer* ASurfaceTexture_dequeueBuffer(ASurfaceTexture* st, int* outSlotid, - android_dataspace* outDataspace, - float* outTransformMatrix, uint32_t* outTransform, - bool* outNewContent, - ASurfaceTexture_createReleaseFence createFence, - ASurfaceTexture_fenceWait fenceWait, - void* fencePassThroughHandle, ARect* currentCrop); +AHardwareBuffer* ASurfaceTexture_dequeueBuffer( + ASurfaceTexture* st, int* outSlotid, android_dataspace* outDataspace, + AHdrMetadataType* outHdrType, android_cta861_3_metadata* outCta861_3, + android_smpte2086_metadata* outSmpte2086, float* outTransformMatrix, uint32_t* outTransform, + bool* outNewContent, ASurfaceTexture_createReleaseFence createFence, + ASurfaceTexture_fenceWait fenceWait, void* fencePassThroughHandle, ARect* currentCrop); } // namespace android diff --git a/libs/nativedisplay/surfacetexture/ImageConsumer.cpp b/libs/nativedisplay/surfacetexture/ImageConsumer.cpp index 365e788ea6..cf16739e89 100644 --- a/libs/nativedisplay/surfacetexture/ImageConsumer.cpp +++ b/libs/nativedisplay/surfacetexture/ImageConsumer.cpp @@ -28,7 +28,8 @@ void ImageConsumer::onReleaseBufferLocked(int buf) { } sp ImageConsumer::dequeueBuffer(int* outSlotid, android_dataspace* outDataspace, - bool* outQueueEmpty, SurfaceTexture& st, + HdrMetadata* outHdrMetadata, bool* outQueueEmpty, + SurfaceTexture& st, SurfaceTexture_createReleaseFence createFence, SurfaceTexture_fenceWait fenceWait, void* fencePassThroughHandle) { @@ -121,6 +122,7 @@ sp ImageConsumer::dequeueBuffer(int* outSlotid, android_dataspace st.computeCurrentTransformMatrixLocked(); *outDataspace = item.mDataSpace; + *outHdrMetadata = item.mHdrMetadata; *outSlotid = slot; return st.mSlots[slot].mGraphicBuffer; } diff --git a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp index 3535e67895..d3d4cbafdf 100644 --- a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp +++ b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp @@ -464,6 +464,7 @@ void SurfaceTexture::dumpLocked(String8& result, const char* prefix) const { } sp SurfaceTexture::dequeueBuffer(int* outSlotid, android_dataspace* outDataspace, + HdrMetadata* outHdrMetadata, float* outTransformMatrix, uint32_t* outTransform, bool* outQueueEmpty, SurfaceTexture_createReleaseFence createFence, @@ -482,8 +483,8 @@ sp SurfaceTexture::dequeueBuffer(int* outSlotid, android_dataspac return buffer; } - buffer = mImageConsumer.dequeueBuffer(outSlotid, outDataspace, outQueueEmpty, *this, - createFence, fenceWait, fencePassThroughHandle); + buffer = mImageConsumer.dequeueBuffer(outSlotid, outDataspace, outHdrMetadata, outQueueEmpty, + *this, createFence, fenceWait, fencePassThroughHandle); memcpy(outTransformMatrix, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix)); *outTransform = mCurrentTransform; *currentCrop = mCurrentCrop; diff --git a/libs/nativedisplay/surfacetexture/surface_texture.cpp b/libs/nativedisplay/surfacetexture/surface_texture.cpp index cc0a12d2c6..39a925f712 100644 --- a/libs/nativedisplay/surfacetexture/surface_texture.cpp +++ b/libs/nativedisplay/surfacetexture/surface_texture.cpp @@ -192,20 +192,23 @@ void ASurfaceTexture_releaseConsumerOwnership(ASurfaceTexture* texture) { texture->consumer->releaseConsumerOwnership(); } -AHardwareBuffer* ASurfaceTexture_dequeueBuffer(ASurfaceTexture* st, int* outSlotid, - android_dataspace* outDataspace, - float* outTransformMatrix, uint32_t* outTransform, - bool* outNewContent, - ASurfaceTexture_createReleaseFence createFence, - ASurfaceTexture_fenceWait fenceWait, void* handle, - ARect* currentCrop) { +AHardwareBuffer* ASurfaceTexture_dequeueBuffer( + ASurfaceTexture* st, int* outSlotid, android_dataspace* outDataspace, + AHdrMetadataType* outHdrType, android_cta861_3_metadata* outCta861_3, + android_smpte2086_metadata* outSmpte2086, float* outTransformMatrix, uint32_t* outTransform, + bool* outNewContent, ASurfaceTexture_createReleaseFence createFence, + ASurfaceTexture_fenceWait fenceWait, void* handle, ARect* currentCrop) { sp buffer; *outNewContent = false; bool queueEmpty; do { - buffer = st->consumer->dequeueBuffer(outSlotid, outDataspace, outTransformMatrix, + HdrMetadata metadata; + buffer = st->consumer->dequeueBuffer(outSlotid, outDataspace, &metadata, outTransformMatrix, outTransform, &queueEmpty, createFence, fenceWait, handle, currentCrop); + *outHdrType = static_cast(metadata.validTypes); + *outCta861_3 = metadata.cta8613; + *outSmpte2086 = metadata.smpte2086; if (!queueEmpty) { *outNewContent = true; } -- cgit v1.2.3-59-g8ed1b From 51891d84fde44c1e2def7e56d6f56cdeb9805cad Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 22 Nov 2021 09:53:08 -0800 Subject: Move ui/GraphicsTypes into include_types So that libhwui can use it since libhwui links in libui-types rather than the entire libui library due to prior mainline work Bug: 200309590 Test: builds, boots Change-Id: Ia50853962f15eae5f0ced78de3ff0e8a690908d0 --- libs/ui/include_types/ui/GraphicTypes.h | 1 + 1 file changed, 1 insertion(+) create mode 120000 libs/ui/include_types/ui/GraphicTypes.h diff --git a/libs/ui/include_types/ui/GraphicTypes.h b/libs/ui/include_types/ui/GraphicTypes.h new file mode 120000 index 0000000000..b1859e0f51 --- /dev/null +++ b/libs/ui/include_types/ui/GraphicTypes.h @@ -0,0 +1 @@ +../../include/ui/GraphicTypes.h \ No newline at end of file -- cgit v1.2.3-59-g8ed1b From ac331c52c5fe0edba5bff7a671bdac724d99fb01 Mon Sep 17 00:00:00 2001 From: Jaineel Mehta Date: Mon, 29 Nov 2021 21:38:10 +0000 Subject: Revert "SF: Update InputFlinger outside main thread" This reverts commit 42a27b5657975485a72033736f37bfe6de0e21a8. Reason for revert: Bug: 207839663 Change-Id: Ic066d5a44339128a59e8aa3bb488a41cad13cf76 --- libs/gui/LayerState.cpp | 4 +- services/surfaceflinger/BackgroundExecutor.cpp | 8 ++-- services/surfaceflinger/BackgroundExecutor.h | 7 ++- services/surfaceflinger/SurfaceFlinger.cpp | 61 ++++++++++---------------- services/surfaceflinger/SurfaceFlinger.h | 4 +- 5 files changed, 32 insertions(+), 52 deletions(-) diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index bb7e1a48f7..f848e4ffde 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -546,7 +546,9 @@ bool InputWindowCommands::merge(const InputWindowCommands& other) { } bool InputWindowCommands::empty() const { - return focusRequests.empty() && !syncInputWindows; + bool empty = true; + empty = focusRequests.empty() && !syncInputWindows; + return empty; } void InputWindowCommands::clear() { diff --git a/services/surfaceflinger/BackgroundExecutor.cpp b/services/surfaceflinger/BackgroundExecutor.cpp index de8e6b380f..3663cdb0ec 100644 --- a/services/surfaceflinger/BackgroundExecutor.cpp +++ b/services/surfaceflinger/BackgroundExecutor.cpp @@ -32,9 +32,7 @@ BackgroundExecutor::BackgroundExecutor() : Singleton() { std::vector> tasks; { std::unique_lock lock(mMutex); - android::base::ScopedLockAssertion assumeLock(mMutex); - mWorkAvailableCv.wait(lock, - [&]() REQUIRES(mMutex) { return mDone || !mTasks.empty(); }); + mWorkAvailableCv.wait(lock, [&]() { return mDone || !mTasks.empty(); }); tasks = std::move(mTasks); mTasks.clear(); done = mDone; @@ -49,7 +47,7 @@ BackgroundExecutor::BackgroundExecutor() : Singleton() { BackgroundExecutor::~BackgroundExecutor() { { - std::scoped_lock lock(mMutex); + std::unique_lock lock(mMutex); mDone = true; mWorkAvailableCv.notify_all(); } @@ -59,7 +57,7 @@ BackgroundExecutor::~BackgroundExecutor() { } void BackgroundExecutor::execute(std::function task) { - std::scoped_lock lock(mMutex); + std::unique_lock lock(mMutex); mTasks.emplace_back(std::move(task)); mWorkAvailableCv.notify_all(); } diff --git a/services/surfaceflinger/BackgroundExecutor.h b/services/surfaceflinger/BackgroundExecutor.h index 6db7dda7aa..6f6d305280 100644 --- a/services/surfaceflinger/BackgroundExecutor.h +++ b/services/surfaceflinger/BackgroundExecutor.h @@ -16,7 +16,6 @@ #pragma once -#include #include #include #include @@ -34,10 +33,10 @@ public: private: std::mutex mMutex; - std::condition_variable mWorkAvailableCv GUARDED_BY(mMutex); - bool mDone GUARDED_BY(mMutex) = false; - std::vector> mTasks GUARDED_BY(mMutex); + std::condition_variable mWorkAvailableCv; std::thread mThread; + bool mDone = false; + std::vector> mTasks; }; } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 27fc942915..93f8406319 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -93,7 +93,6 @@ #include #include -#include "BackgroundExecutor.h" #include "BufferLayer.h" #include "BufferQueueLayer.h" #include "BufferStateLayer.h" @@ -509,7 +508,7 @@ void SurfaceFlinger::binderDied(const wp&) { mBootFinished = false; // Sever the link to inputflinger since it's gone as well. - BackgroundExecutor::getInstance().execute([=] { mInputFlinger = nullptr; }); + static_cast(mScheduler->schedule([=] { mInputFlinger = nullptr; })); // restore initial conditions (default device unblank, etc) initializeDisplays(); @@ -720,15 +719,13 @@ void SurfaceFlinger::bootFinished() { sp input(defaultServiceManager()->getService(String16("inputflinger"))); - BackgroundExecutor::getInstance().execute([=] { + static_cast(mScheduler->schedule([=] { if (input == nullptr) { ALOGE("Failed to link to input service"); } else { mInputFlinger = interface_cast(input); } - }); - static_cast(mScheduler->schedule([=] { readPersistentProperties(); mPowerAdvisor.onBootFinished(); mBootStage = BootStage::FINISHED; @@ -3007,48 +3004,32 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { void SurfaceFlinger::updateInputFlinger() { ATRACE_CALL(); - std::vector windowInfos; - std::vector displayInfos; - bool updateWindowInfo = false; + if (!mInputFlinger) { + return; + } + if (mVisibleRegionsDirty || mInputInfoChanged) { mInputInfoChanged = false; - updateWindowInfo = true; - buildWindowInfos(windowInfos, displayInfos); - } - if (!updateWindowInfo && mInputWindowCommands.empty()) { - return; + notifyWindowInfos(); + } else if (mInputWindowCommands.syncInputWindows) { + // If the caller requested to sync input windows, but there are no + // changes to input windows, notify immediately. + windowInfosReported(); } - BackgroundExecutor::getInstance().execute([updateWindowInfo, - windowInfos = std::move(windowInfos), - displayInfos = std::move(displayInfos), - inputWindowCommands = - std::move(mInputWindowCommands), - this]() { - ATRACE_NAME("BackgroundExecutor::updateInputFlinger"); - if (!mInputFlinger) { - return; - } - if (updateWindowInfo) { - mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos, - inputWindowCommands.syncInputWindows); - } else if (inputWindowCommands.syncInputWindows) { - // If the caller requested to sync input windows, but there are no - // changes to input windows, notify immediately. - windowInfosReported(); - } - for (const auto& focusRequest : inputWindowCommands.focusRequests) { - mInputFlinger->setFocusedWindow(focusRequest); - } - }); + for (const auto& focusRequest : mInputWindowCommands.focusRequests) { + mInputFlinger->setFocusedWindow(focusRequest); + } mInputWindowCommands.clear(); } -void SurfaceFlinger::buildWindowInfos(std::vector& outWindowInfos, - std::vector& outDisplayInfos) { +void SurfaceFlinger::notifyWindowInfos() { + std::vector windowInfos; + std::vector displayInfos; std::unordered_map> inputDisplayDetails; + for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { if (!display->receivesInput()) { continue; @@ -3062,7 +3043,7 @@ void SurfaceFlinger::buildWindowInfos(std::vector& outWindowInfos, layerStackId); continue; } - outDisplayInfos.emplace_back(info); + displayInfos.emplace_back(info); } mDrawingState.traverseInReverseZOrder([&](Layer* layer) { @@ -3082,8 +3063,10 @@ void SurfaceFlinger::buildWindowInfos(std::vector& outWindowInfos, layer->getDebugName(), layerStackId); } - outWindowInfos.push_back(layer->fillInputInfo(displayTransform, isSecure)); + windowInfos.push_back(layer->fillInputInfo(displayTransform, isSecure)); }); + mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos, + mInputWindowCommands.syncInputWindows); } void SurfaceFlinger::updateCursorAsync() { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 353f747ce5..6093be91f9 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -689,8 +689,7 @@ private: void updateLayerGeometry(); void updateInputFlinger(); - void buildWindowInfos(std::vector& outWindowInfos, - std::vector& outDisplayInfos); + void notifyWindowInfos(); void commitInputWindowCommands() REQUIRES(mStateLock); void updateCursorAsync(); @@ -1290,7 +1289,6 @@ private: const float mInternalDisplayDensity; const float mEmulatedDisplayDensity; - // Should only be accessed by BackgroundExecutor thread. sp mInputFlinger; // Should only be accessed by the main thread. InputWindowCommands mInputWindowCommands; -- cgit v1.2.3-59-g8ed1b From 0cc69e10147af9b6a4f8268164f0a3b61cd4f0a7 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 18 Nov 2021 09:05:49 -0800 Subject: SF: Track starting layer state with transaction tracing In order to recreate the layer state from transaction traces, we need to know the starting layer state. We need to start with an initial state, then replay the transactions from the trace to recreate the layer states. Keeping track of the initial layer state while maintaining a ring buffer of transactions is expensive since it would require accessing the drawing state from the tracing thread. This cl builds and updates a transaction that will recreate the layer's starting state. As transactions are evicted from the ring buffer, they are used to update the starting state transactions. Test: presubmit Bug: 200284593 Change-Id: Ifaba8fb061fca4acc15df661483217552011aa09 --- services/surfaceflinger/SurfaceFlinger.cpp | 11 ++ services/surfaceflinger/Tracing/LayerTracing.cpp | 1 + services/surfaceflinger/Tracing/RingBuffer.h | 35 ++-- .../Tracing/TransactionProtoParser.cpp | 2 +- .../Tracing/TransactionProtoParser.h | 2 +- .../surfaceflinger/Tracing/TransactionTracing.cpp | 184 +++++++++++++++++---- .../surfaceflinger/Tracing/TransactionTracing.h | 29 +++- .../surfaceflinger/layerproto/transactions.proto | 6 +- .../tests/unittests/TransactionTracingTest.cpp | 183 ++++++++++++++++++-- 9 files changed, 380 insertions(+), 73 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7a8968be19..522ae44c67 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4355,6 +4355,16 @@ status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, sp* outHa return result; } + int parentId = -1; + // We can safely promote the layer in binder thread because we have a strong reference + // to the layer's handle inside this scope or we were passed in a sp reference to the layer. + sp parentSp = parent.promote(); + if (parentSp != nullptr) { + parentId = parentSp->getSequence(); + } + mTransactionTracing.onLayerAdded((*outHandle)->localBinder(), layer->sequence, args.name, + args.flags, parentId); + setTransactionFlags(eTransactionNeeded); *outLayerId = layer->sequence; return result; @@ -6592,6 +6602,7 @@ void SurfaceFlinger::onLayerDestroyed(Layer* layer) { if (!layer->isRemovedFromCurrentState()) { mScheduler->deregisterLayer(layer); } + mTransactionTracing.onLayerRemoved(layer->getSequence()); } void SurfaceFlinger::onLayerUpdate() { diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp index 84890eefd1..d136e0b6c8 100644 --- a/services/surfaceflinger/Tracing/LayerTracing.cpp +++ b/services/surfaceflinger/Tracing/LayerTracing.cpp @@ -53,6 +53,7 @@ bool LayerTracing::disable() { mEnabled = false; LayersTraceFileProto fileProto = createTraceFileProto(); mBuffer->writeToFile(fileProto, FILE_NAME); + mBuffer->reset(); return true; } diff --git a/services/surfaceflinger/Tracing/RingBuffer.h b/services/surfaceflinger/Tracing/RingBuffer.h index 63a27869b6..281cd1951f 100644 --- a/services/surfaceflinger/Tracing/RingBuffer.h +++ b/services/surfaceflinger/Tracing/RingBuffer.h @@ -39,26 +39,28 @@ public: void setSize(size_t newSize) { mSizeInBytes = newSize; } EntryProto& front() { return mStorage.front(); } const EntryProto& front() const { return mStorage.front(); } + const EntryProto& back() const { return mStorage.back(); } - void reset(size_t newSize) { + void reset() { // use the swap trick to make sure memory is released - std::queue().swap(mStorage); - mSizeInBytes = newSize; + std::deque().swap(mStorage); mUsedInBytes = 0U; } - void flush(FileProto& fileProto) { - fileProto.mutable_entry()->Reserve(static_cast(mStorage.size())); - while (!mStorage.empty()) { - auto entry = fileProto.add_entry(); - entry->Swap(&mStorage.front()); - mStorage.pop(); + + void writeToProto(FileProto& fileProto) { + fileProto.mutable_entry()->Reserve(static_cast(mStorage.size()) + + fileProto.entry().size()); + for (const EntryProto& entry : mStorage) { + EntryProto* entryProto = fileProto.add_entry(); + *entryProto = entry; } } status_t writeToFile(FileProto& fileProto, std::string filename) { ATRACE_CALL(); + writeToProto(fileProto); std::string output; - if (!writeToString(fileProto, &output)) { + if (!fileProto.SerializeToString(&output)) { ALOGE("Could not serialize proto."); return UNKNOWN_ERROR; } @@ -72,13 +74,6 @@ public: return NO_ERROR; } - bool writeToString(FileProto& fileProto, std::string* outString) { - ATRACE_CALL(); - flush(fileProto); - reset(mSizeInBytes); - return fileProto.SerializeToString(outString); - } - std::vector emplace(EntryProto&& proto) { std::vector replacedEntries; size_t protoSize = static_cast(proto.ByteSize()); @@ -88,10 +83,10 @@ public: } mUsedInBytes -= static_cast(mStorage.front().ByteSize()); replacedEntries.emplace_back(mStorage.front()); - mStorage.pop(); + mStorage.pop_front(); } mUsedInBytes += protoSize; - mStorage.emplace(); + mStorage.emplace_back(); mStorage.back().Swap(&proto); return replacedEntries; } @@ -112,7 +107,7 @@ public: private: size_t mUsedInBytes = 0U; size_t mSizeInBytes = 0U; - std::queue mStorage; + std::deque mStorage; }; } // namespace android diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp index d1dc07639a..7e12313af1 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp @@ -43,7 +43,7 @@ proto::TransactionState TransactionProtoParser::toProto(const TransactionState& } proto::TransactionState TransactionProtoParser::toProto( - std::vector> states) { + const std::unordered_map states) { proto::TransactionState proto; for (auto& [layerId, state] : states) { proto::LayerState layerProto = toProto(state, nullptr); diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h index e8a139fb98..619ee058bb 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.h +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h @@ -51,7 +51,7 @@ public: static proto::TransactionState toProto(const TransactionState&, LayerHandleToIdFn getLayerIdFn, DisplayHandleToIdFn getDisplayIdFn); static proto::TransactionState toProto( - std::vector>); + const std::unordered_map); static proto::LayerCreationArgs toProto(const TracingLayerCreationArgs& args); diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp index 758bd31563..cf488c26f9 100644 --- a/services/surfaceflinger/Tracing/TransactionTracing.cpp +++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp @@ -41,6 +41,7 @@ bool TransactionTracing::enable() { return false; } mBuffer->setSize(mBufferSizeInBytes); + mStartingTimestamp = systemTime(); mEnabled = true; { std::scoped_lock lock(mMainThreadLock); @@ -68,9 +69,11 @@ bool TransactionTracing::disable() { } mEnabled = false; - proto::TransactionTraceFile fileProto = createTraceFileProto(); - mBuffer->writeToFile(fileProto, FILE_NAME); + writeToFileLocked(); + mBuffer->reset(); mQueuedTransactions.clear(); + mStartingStates.clear(); + mLayerHandles.clear(); return true; } @@ -84,7 +87,12 @@ status_t TransactionTracing::writeToFile() { if (!mEnabled) { return STATUS_OK; } + return writeToFileLocked(); +} + +status_t TransactionTracing::writeToFileLocked() { proto::TransactionTraceFile fileProto = createTraceFileProto(); + addStartingStateToProtoLocked(fileProto); return mBuffer->writeToFile(fileProto, FILE_NAME); } @@ -105,8 +113,10 @@ void TransactionTracing::dump(std::string& result) const { std::scoped_lock lock(mTraceLock); base::StringAppendF(&result, "Transaction tracing state: %s\n", mEnabled ? "enabled" : "disabled"); - base::StringAppendF(&result, " queued transactions: %d\n", - static_cast(mQueuedTransactions.size())); + base::StringAppendF(&result, + " queued transactions=%zu created layers=%zu handles=%zu states=%zu\n", + mQueuedTransactions.size(), mCreatedLayers.size(), mLayerHandles.size(), + mStartingStates.size()); mBuffer->dump(result); } @@ -117,7 +127,10 @@ void TransactionTracing::addQueuedTransaction(const TransactionState& transactio return; } mQueuedTransactions[transaction.id] = - TransactionProtoParser::toProto(transaction, nullptr, nullptr); + TransactionProtoParser::toProto(transaction, + std::bind(&TransactionTracing::getLayerIdLocked, this, + std::placeholders::_1), + nullptr); } void TransactionTracing::addCommittedTransactions(std::vector& transactions, @@ -130,25 +143,14 @@ void TransactionTracing::addCommittedTransactions(std::vector& committedTransactions.transactionIds.emplace_back(transaction.id); } - // Try to acquire the lock from main thread, but don't block if we cannot acquire the lock. Add - // it to pending transactions that we can collect later. - if (mMainThreadLock.try_lock()) { - // We got the lock! Collect any pending transactions and continue. - mCommittedTransactions.insert(mCommittedTransactions.end(), - std::make_move_iterator(mPendingTransactions.begin()), - std::make_move_iterator(mPendingTransactions.end())); - mPendingTransactions.clear(); - mCommittedTransactions.emplace_back(committedTransactions); - mTransactionsAvailableCv.notify_one(); - mMainThreadLock.unlock(); - } else { - mPendingTransactions.emplace_back(committedTransactions); - } + mPendingTransactions.emplace_back(committedTransactions); + tryPushToTracingThread(); } void TransactionTracing::loop() { while (true) { std::vector committedTransactions; + std::vector removedLayers; { std::unique_lock lock(mMainThreadLock); base::ScopedLockAssertion assumeLocked(mMainThreadLock); @@ -157,19 +159,22 @@ void TransactionTracing::loop() { }); if (mDone) { mCommittedTransactions.clear(); + mRemovedLayers.clear(); break; } + + removedLayers = std::move(mRemovedLayers); + mRemovedLayers.clear(); committedTransactions = std::move(mCommittedTransactions); mCommittedTransactions.clear(); } // unlock mMainThreadLock - addEntry(committedTransactions); - - mTransactionsAddedToBufferCv.notify_one(); + addEntry(committedTransactions, removedLayers); } } -void TransactionTracing::addEntry(const std::vector& committedTransactions) { +void TransactionTracing::addEntry(const std::vector& committedTransactions, + const std::vector& removedLayers) { ATRACE_CALL(); std::scoped_lock lock(mTraceLock); std::vector removedEntries; @@ -177,6 +182,15 @@ void TransactionTracing::addEntry(const std::vector& comm proto::TransactionTraceEntry entryProto; entryProto.set_elapsed_realtime_nanos(entry.timestamp); entryProto.set_vsync_id(entry.vsyncId); + entryProto.mutable_added_layers()->Reserve(static_cast(mCreatedLayers.size())); + for (auto& newLayer : mCreatedLayers) { + entryProto.mutable_added_layers()->Add(std::move(newLayer)); + } + entryProto.mutable_removed_layers()->Reserve(static_cast(removedLayers.size())); + for (auto& removedLayer : removedLayers) { + entryProto.mutable_removed_layers()->Add(removedLayer); + } + mCreatedLayers.clear(); entryProto.mutable_transactions()->Reserve( static_cast(entry.transactionIds.size())); for (const uint64_t& id : entry.transactionIds) { @@ -188,16 +202,128 @@ void TransactionTracing::addEntry(const std::vector& comm ALOGE("Could not find transaction id %" PRIu64, id); } } - mBuffer->emplace(std::move(entryProto)); + std::vector entries = mBuffer->emplace(std::move(entryProto)); + removedEntries.insert(removedEntries.end(), std::make_move_iterator(entries.begin()), + std::make_move_iterator(entries.end())); + } + + for (const proto::TransactionTraceEntry& removedEntry : removedEntries) { + updateStartingStateLocked(removedEntry); } + mTransactionsAddedToBufferCv.notify_one(); } -void TransactionTracing::flush() { - std::unique_lock lock(mMainThreadLock); - base::ScopedLockAssertion assumeLocked(mMainThreadLock); - mTransactionsAddedToBufferCv.wait(lock, [&]() REQUIRES(mMainThreadLock) { - return mCommittedTransactions.empty(); +void TransactionTracing::flush(int64_t vsyncId) { + while (!mPendingTransactions.empty() || !mPendingRemovedLayers.empty()) { + tryPushToTracingThread(); + } + std::unique_lock lock(mTraceLock); + base::ScopedLockAssertion assumeLocked(mTraceLock); + mTransactionsAddedToBufferCv.wait(lock, [&]() REQUIRES(mTraceLock) { + return mBuffer->used() > 0 && mBuffer->back().vsync_id() >= vsyncId; }); } +void TransactionTracing::onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name, + uint32_t flags, int parentId) { + std::scoped_lock lock(mTraceLock); + TracingLayerCreationArgs args{layerId, name, flags, parentId}; + mLayerHandles[layerHandle] = layerId; + mCreatedLayers.emplace_back(TransactionProtoParser::toProto(args)); +} + +void TransactionTracing::onLayerRemoved(int32_t layerId) { + mPendingRemovedLayers.emplace_back(layerId); + tryPushToTracingThread(); +} + +void TransactionTracing::tryPushToTracingThread() { + // Try to acquire the lock from main thread. + if (mMainThreadLock.try_lock()) { + // We got the lock! Collect any pending transactions and continue. + mCommittedTransactions.insert(mCommittedTransactions.end(), + std::make_move_iterator(mPendingTransactions.begin()), + std::make_move_iterator(mPendingTransactions.end())); + mPendingTransactions.clear(); + mRemovedLayers.insert(mRemovedLayers.end(), mPendingRemovedLayers.begin(), + mPendingRemovedLayers.end()); + mPendingRemovedLayers.clear(); + mTransactionsAvailableCv.notify_one(); + mMainThreadLock.unlock(); + } else { + ALOGV("Couldn't get lock"); + } +} + +int32_t TransactionTracing::getLayerIdLocked(const sp& layerHandle) { + if (layerHandle == nullptr) { + return -1; + } + auto it = mLayerHandles.find(layerHandle->localBinder()); + return it == mLayerHandles.end() ? -1 : it->second; +} + +void TransactionTracing::updateStartingStateLocked( + const proto::TransactionTraceEntry& removedEntry) { + // Keep track of layer starting state so we can reconstruct the layer state as we purge + // transactions from the buffer. + for (const proto::LayerCreationArgs& addedLayer : removedEntry.added_layers()) { + TracingLayerState& startingState = mStartingStates[addedLayer.layer_id()]; + startingState.layerId = addedLayer.layer_id(); + startingState.name = addedLayer.name(); + startingState.layerCreationFlags = addedLayer.flags(); + startingState.parentId = addedLayer.parent_id(); + } + + // Merge layer states to starting transaction state. + for (const proto::TransactionState& transaction : removedEntry.transactions()) { + for (const proto::LayerState& layerState : transaction.layer_changes()) { + auto it = mStartingStates.find(layerState.layer_id()); + if (it == mStartingStates.end()) { + ALOGE("Could not find layer id %d", layerState.layer_id()); + continue; + } + TransactionProtoParser::fromProto(layerState, nullptr, it->second); + } + } + + // Clean up stale starting states since the layer has been removed and the buffer does not + // contain any references to the layer. + for (const int32_t removedLayerId : removedEntry.removed_layers()) { + auto it = std::find_if(mLayerHandles.begin(), mLayerHandles.end(), + [removedLayerId](auto& layer) { + return layer.second == removedLayerId; + }); + if (it != mLayerHandles.end()) { + mLayerHandles.erase(it); + } + mStartingStates.erase(removedLayerId); + } +} + +void TransactionTracing::addStartingStateToProtoLocked(proto::TransactionTraceFile& proto) { + proto::TransactionTraceEntry* entryProto = proto.add_entry(); + entryProto->set_elapsed_realtime_nanos(mStartingTimestamp); + entryProto->set_vsync_id(0); + entryProto->mutable_added_layers()->Reserve(static_cast(mStartingStates.size())); + for (auto& [layerId, state] : mStartingStates) { + TracingLayerCreationArgs args{layerId, state.name, state.layerCreationFlags, + state.parentId}; + entryProto->mutable_added_layers()->Add(TransactionProtoParser::toProto(args)); + } + + proto::TransactionState transactionProto = TransactionProtoParser::toProto(mStartingStates); + transactionProto.set_vsync_id(0); + transactionProto.set_post_time(mStartingTimestamp); + entryProto->mutable_transactions()->Add(std::move(transactionProto)); +} + +proto::TransactionTraceFile TransactionTracing::writeToProto() { + std::scoped_lock lock(mTraceLock); + proto::TransactionTraceFile proto = createTraceFileProto(); + addStartingStateToProtoLocked(proto); + mBuffer->writeToProto(proto); + return proto; +} + } // namespace android diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h index d92ab014e1..0aa22ede26 100644 --- a/services/surfaceflinger/Tracing/TransactionTracing.h +++ b/services/surfaceflinger/Tracing/TransactionTracing.h @@ -62,6 +62,9 @@ public: void addCommittedTransactions(std::vector& transactions, int64_t vsyncId); status_t writeToFile(); void setBufferSize(size_t bufferSizeInBytes); + void onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name, uint32_t flags, + int parentId); + void onLayerRemoved(int layerId); void dump(std::string&) const; static constexpr auto CONTINUOUS_TRACING_BUFFER_SIZE = 512 * 1024; static constexpr auto ACTIVE_TRACING_BUFFER_SIZE = 100 * 1024 * 1024; @@ -78,6 +81,12 @@ private: size_t mBufferSizeInBytes GUARDED_BY(mTraceLock) = CONTINUOUS_TRACING_BUFFER_SIZE; std::unordered_map mQueuedTransactions GUARDED_BY(mTraceLock); + nsecs_t mStartingTimestamp GUARDED_BY(mTraceLock); + std::vector mCreatedLayers GUARDED_BY(mTraceLock); + std::unordered_map mLayerHandles + GUARDED_BY(mTraceLock); + std::unordered_map mStartingStates + GUARDED_BY(mTraceLock); // We do not want main thread to block so main thread will try to acquire mMainThreadLock, // otherwise will push data to temporary container. @@ -93,15 +102,25 @@ private: }; std::vector mCommittedTransactions GUARDED_BY(mMainThreadLock); std::vector mPendingTransactions; // only accessed by main thread - proto::TransactionTraceFile createTraceFileProto() const; + std::vector mRemovedLayers GUARDED_BY(mMainThreadLock); + std::vector mPendingRemovedLayers; // only accessed by main thread + + proto::TransactionTraceFile createTraceFileProto() const; void loop(); - void addEntry(const std::vector& committedTransactions) - EXCLUDES(mTraceLock); + void addEntry(const std::vector& committedTransactions, + const std::vector& removedLayers) EXCLUDES(mTraceLock); + int32_t getLayerIdLocked(const sp& layerHandle) REQUIRES(mTraceLock); + void tryPushToTracingThread() EXCLUDES(mMainThreadLock); + void addStartingStateToProtoLocked(proto::TransactionTraceFile& proto) REQUIRES(mTraceLock); + void updateStartingStateLocked(const proto::TransactionTraceEntry& entry) REQUIRES(mTraceLock); + status_t writeToFileLocked() REQUIRES(mTraceLock); // TEST - // Wait until all the committed transactions are added to the buffer. - void flush() EXCLUDES(mMainThreadLock); + // Wait until all the committed transactions for the specified vsync id are added to the buffer. + void flush(int64_t vsyncId) EXCLUDES(mMainThreadLock); + // Return buffer contents as trace file proto + proto::TransactionTraceFile writeToProto() EXCLUDES(mMainThreadLock); }; } // namespace android diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto index edeacfa72a..10222cc283 100644 --- a/services/surfaceflinger/layerproto/transactions.proto +++ b/services/surfaceflinger/layerproto/transactions.proto @@ -42,8 +42,10 @@ message TransactionTraceEntry { int64 elapsed_realtime_nanos = 1; int64 vsync_id = 2; repeated TransactionState transactions = 3; - repeated LayerCreationArgs new_layers = 4; - repeated DisplayState new_displays = 5; + repeated LayerCreationArgs added_layers = 4; + repeated int32 removed_layers = 5; + repeated DisplayState added_displays = 6; + repeated int32 removed_displays = 7; } message LayerCreationArgs { diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp index 2afa68ab68..ffe5671935 100644 --- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp @@ -28,11 +28,14 @@ namespace android { class TransactionTracingTest : public testing::Test { protected: + static constexpr size_t SMALL_BUFFER_SIZE = 1024; std::unique_ptr mTracing; - void SetUp() override { mTracing = std::make_unique(); } - void TearDown() override { mTracing.reset(); } + void TearDown() override { + mTracing->disable(); + mTracing.reset(); + } auto getCommittedTransactions() { std::scoped_lock lock(mTracing->mMainThreadLock); @@ -49,7 +52,7 @@ protected: return mTracing->mBuffer->used(); } - auto flush() { return mTracing->flush(); } + auto flush(int64_t vsyncId) { return mTracing->flush(vsyncId); } auto bufferFront() { std::scoped_lock lock(mTracing->mTraceLock); @@ -61,12 +64,28 @@ protected: return mTracing->mThread.joinable(); } - std::string writeToString() { + proto::TransactionTraceFile writeToProto() { return mTracing->writeToProto(); } + + auto getCreatedLayers() { + std::scoped_lock lock(mTracing->mTraceLock); + return mTracing->mCreatedLayers; + } + + auto getStartingStates() { std::scoped_lock lock(mTracing->mTraceLock); - std::string output; - proto::TransactionTraceFile fileProto = mTracing->createTraceFileProto(); - mTracing->mBuffer->writeToString(fileProto, &output); - return output; + return mTracing->mStartingStates; + } + + void queueAndCommitTransaction(int64_t vsyncId) { + TransactionState transaction; + transaction.id = static_cast(vsyncId * 3); + transaction.originUid = 1; + transaction.originPid = 2; + mTracing->addQueuedTransaction(transaction); + std::vector transactions; + transactions.emplace_back(transaction); + mTracing->addCommittedTransactions(transactions, vsyncId); + flush(vsyncId); } // Test that we clean up the tracing thread and free any memory allocated. @@ -76,6 +95,7 @@ protected: EXPECT_EQ(getCommittedTransactions().size(), 0u); EXPECT_EQ(getQueuedTransactions().size(), 0u); EXPECT_EQ(getUsedBufferSize(), 0u); + EXPECT_EQ(getStartingStates().size(), 0u); } void verifyEntry(const proto::TransactionTraceEntry& actualProto, @@ -122,17 +142,150 @@ TEST_F(TransactionTracingTest, addTransactions) { std::vector secondTransactionSet = std::vector(transactions.begin(), transactions.begin() + 50); mTracing->addCommittedTransactions(secondTransactionSet, secondTransactionSetVsyncId); - flush(); + flush(secondTransactionSetVsyncId); - std::string protoString = writeToString(); - proto::TransactionTraceFile proto; - proto.ParseFromString(protoString); - EXPECT_EQ(proto.entry().size(), 2); - verifyEntry(proto.entry(0), firstTransactionSet, firstTransactionSetVsyncId); - verifyEntry(proto.entry(1), secondTransactionSet, secondTransactionSetVsyncId); + proto::TransactionTraceFile proto = writeToProto(); + EXPECT_EQ(proto.entry().size(), 3); + // skip starting entry + verifyEntry(proto.entry(1), firstTransactionSet, firstTransactionSetVsyncId); + verifyEntry(proto.entry(2), secondTransactionSet, secondTransactionSetVsyncId); mTracing->disable(); verifyDisabledTracingState(); } +class TransactionTracingLayerHandlingTest : public TransactionTracingTest { +protected: + void SetUp() override { + TransactionTracingTest::SetUp(); + mTracing->enable(); + // add layers + mTracing->setBufferSize(SMALL_BUFFER_SIZE); + const sp fakeLayerHandle = new BBinder(); + mTracing->onLayerAdded(fakeLayerHandle->localBinder(), mParentLayerId, "parent", + 123 /* flags */, -1 /* parentId */); + const sp fakeChildLayerHandle = new BBinder(); + mTracing->onLayerAdded(fakeChildLayerHandle->localBinder(), 2 /* layerId */, "child", + 456 /* flags */, mParentLayerId); + + // add some layer transaction + { + TransactionState transaction; + transaction.id = 50; + ComposerState layerState; + layerState.state.surface = fakeLayerHandle; + layerState.state.what = layer_state_t::eLayerChanged; + layerState.state.z = 42; + transaction.states.add(layerState); + ComposerState childState; + childState.state.surface = fakeChildLayerHandle; + layerState.state.z = 43; + transaction.states.add(childState); + mTracing->addQueuedTransaction(transaction); + + std::vector transactions; + transactions.emplace_back(transaction); + VSYNC_ID_FIRST_LAYER_CHANGE = ++mVsyncId; + mTracing->addCommittedTransactions(transactions, VSYNC_ID_FIRST_LAYER_CHANGE); + flush(VSYNC_ID_FIRST_LAYER_CHANGE); + } + + // add transactions that modify the layer state further so we can test that layer state + // gets merged + { + TransactionState transaction; + transaction.id = 51; + ComposerState layerState; + layerState.state.surface = fakeLayerHandle; + layerState.state.what = layer_state_t::eLayerChanged | layer_state_t::ePositionChanged; + layerState.state.z = 41; + layerState.state.x = 22; + transaction.states.add(layerState); + mTracing->addQueuedTransaction(transaction); + + std::vector transactions; + transactions.emplace_back(transaction); + VSYNC_ID_SECOND_LAYER_CHANGE = ++mVsyncId; + mTracing->addCommittedTransactions(transactions, VSYNC_ID_SECOND_LAYER_CHANGE); + flush(VSYNC_ID_SECOND_LAYER_CHANGE); + } + + // remove child layer + mTracing->onLayerRemoved(2); + VSYNC_ID_CHILD_LAYER_REMOVED = ++mVsyncId; + queueAndCommitTransaction(VSYNC_ID_CHILD_LAYER_REMOVED); + + // remove layer + mTracing->onLayerRemoved(1); + queueAndCommitTransaction(++mVsyncId); + } + + void TearDown() override { + mTracing->disable(); + verifyDisabledTracingState(); + TransactionTracingTest::TearDown(); + } + + int mParentLayerId = 1; + int64_t mVsyncId = 0; + int64_t VSYNC_ID_FIRST_LAYER_CHANGE; + int64_t VSYNC_ID_SECOND_LAYER_CHANGE; + int64_t VSYNC_ID_CHILD_LAYER_REMOVED; +}; + +TEST_F(TransactionTracingLayerHandlingTest, addStartingState) { + // add transactions until we drop the transaction with the first layer change + while (bufferFront().vsync_id() <= VSYNC_ID_FIRST_LAYER_CHANGE) { + queueAndCommitTransaction(++mVsyncId); + } + proto::TransactionTraceFile proto = writeToProto(); + // verify we can still retrieve the layer change from the first entry containing starting + // states. + EXPECT_GT(proto.entry().size(), 0); + EXPECT_GT(proto.entry(0).transactions().size(), 0); + EXPECT_GT(proto.entry(0).added_layers().size(), 0); + EXPECT_GT(proto.entry(0).transactions(0).layer_changes().size(), 0); + EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).z(), 42); +} + +TEST_F(TransactionTracingLayerHandlingTest, updateStartingState) { + // add transactions until we drop the transaction with the second layer change + while (bufferFront().vsync_id() <= VSYNC_ID_SECOND_LAYER_CHANGE) { + queueAndCommitTransaction(++mVsyncId); + } + proto::TransactionTraceFile proto = writeToProto(); + // verify starting states are updated correctly + EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).z(), 41); +} + +TEST_F(TransactionTracingLayerHandlingTest, removeStartingState) { + // add transactions until we drop the transaction which removes the child layer + while (bufferFront().vsync_id() <= VSYNC_ID_CHILD_LAYER_REMOVED) { + queueAndCommitTransaction(++mVsyncId); + } + proto::TransactionTraceFile proto = writeToProto(); + // verify the child layer has been removed from the trace + EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 1); + EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).layer_id(), mParentLayerId); +} + +TEST_F(TransactionTracingLayerHandlingTest, startingStateSurvivesBufferFlush) { + // add transactions until we drop the transaction with the second layer change + while (bufferFront().vsync_id() <= VSYNC_ID_SECOND_LAYER_CHANGE) { + queueAndCommitTransaction(++mVsyncId); + } + proto::TransactionTraceFile proto = writeToProto(); + // verify we have two starting states + EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 2); + + // Continue adding transactions until child layer is removed + while (bufferFront().vsync_id() <= VSYNC_ID_CHILD_LAYER_REMOVED) { + queueAndCommitTransaction(++mVsyncId); + } + proto = writeToProto(); + // verify we still have the parent layer state + EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 1); + EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).layer_id(), mParentLayerId); +} + } // namespace android -- cgit v1.2.3-59-g8ed1b From 3bea4255568e412b27a60eff090baf95564596e3 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 30 Nov 2021 23:18:13 +0000 Subject: Trace VsyncId in transactionIsReadyToBeApplied Change-Id: Iec16e5fbfec51979ca24e351acd7241d059d3eb9 Test: systrace --- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a648797e6c..0cdbdbd02c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3663,7 +3663,7 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied( const std::unordered_set, ISurfaceComposer::SpHash>& bufferLayersReadyToPresent, bool allowLatchUnsignaled) const { - ATRACE_CALL(); + ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64, info.vsyncId); const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); // Do not present if the desiredPresentTime has not passed unless it is more than one second // in the future. We ignore timestamps more than 1 second in the future for stability reasons. -- cgit v1.2.3-59-g8ed1b From 97a61b526debef6464e8129a8f83da5d4219fab6 Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Tue, 30 Nov 2021 18:35:53 -0500 Subject: Remove unused bitsPerPixel Bug: none Test: make Change-Id: I226111a7c6e8fb8be6974d180938ebcfafa111e1 --- libs/ui/PixelFormat.cpp | 19 ------------------- libs/ui/include/ui/PixelFormat.h | 1 - 2 files changed, 20 deletions(-) diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp index e88fdd5e84..d1925cb446 100644 --- a/libs/ui/PixelFormat.cpp +++ b/libs/ui/PixelFormat.cpp @@ -39,25 +39,6 @@ uint32_t bytesPerPixel(PixelFormat format) { return 0; } -uint32_t bitsPerPixel(PixelFormat format) { - switch (format) { - case PIXEL_FORMAT_RGBA_FP16: - return 64; - case PIXEL_FORMAT_RGBA_8888: - case PIXEL_FORMAT_RGBX_8888: - case PIXEL_FORMAT_BGRA_8888: - case PIXEL_FORMAT_RGBA_1010102: - return 32; - case PIXEL_FORMAT_RGB_888: - return 24; - case PIXEL_FORMAT_RGB_565: - case PIXEL_FORMAT_RGBA_5551: - case PIXEL_FORMAT_RGBA_4444: - return 16; - } - return 0; -} - // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- diff --git a/libs/ui/include/ui/PixelFormat.h b/libs/ui/include/ui/PixelFormat.h index 02773d92fc..91ff39efd8 100644 --- a/libs/ui/include/ui/PixelFormat.h +++ b/libs/ui/include/ui/PixelFormat.h @@ -67,7 +67,6 @@ enum { typedef int32_t PixelFormat; uint32_t bytesPerPixel(PixelFormat format); -uint32_t bitsPerPixel(PixelFormat format); }; // namespace android -- cgit v1.2.3-59-g8ed1b From cf2f21fd82d1f95b20077fd9a10aeaa6eb4c202e Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Tue, 30 Nov 2021 14:47:02 -0800 Subject: BLASTBufferQueue: Cap shadow queue size during sync While waiting for the transaction commit callback on a previous sync transaction BLASTBufferQueue will halt buffer processing to ensure later frames do not arrive at SurfaceFlinger first. These buffers wait in the shadow queue (tracked by mNumFrameAvailable) to be acquired later. If we end up in a situation where all the buffers are either in a sync transaction or in the shadow queue then dequeue buffer will begin to block. This isn't ideal, as dequeue buffer blocking can cause UI thread to block, aka UI thread can block on RenderThread. However completing the sync transaction (from a previous frame) can also depend on UI thread, aka RenderThread can now block on UI thread (since we need the transaction to apply in order to thaw the shadow queue). In this CL we try and avoid that situation by only keeping 1 frame in the shadow queue while waiting for the sync to complete. If a second frame comes in we will acquire and release the first before acquiring the second. Bug: 200285149 Change-Id: I5072765e7b94820b3e66c557f5a96172ccef8172 --- libs/gui/BLASTBufferQueue.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index f05426f7cf..dd50ca7fff 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -649,6 +649,9 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { // add to shadow queue mNumFrameAvailable++; + if (mWaitForTransactionCallback && mNumFrameAvailable == 2) { + acquireAndReleaseBuffer(); + } ATRACE_INT(mQueuedBufferTrace.c_str(), mNumFrameAvailable + mNumAcquired - mPendingRelease.size()); -- cgit v1.2.3-59-g8ed1b From 16c443c69768038bbc6af46dba59e6de4d16e0b3 Mon Sep 17 00:00:00 2001 From: Ian Elliott Date: Tue, 30 Nov 2021 17:10:32 -0700 Subject: swapchain: Fix MAILBOX and SHARED presentation modes This change undoes two previous changes and fixes the original performance problem reported with b/182887411. By default, Vulkan swapchains should use: - 3 images for FIFO (unless limited or increased from below) - 1 images for SHARED This reverts the following commits: - commit 148bad076ef46297e516b650007852937a506c8b. "swapchain: increase the minimal buffer count to 3" - commit ef14146f7de705c2facfc8c470ea100503dbdb57. "swapchain: always return a signle image for shared presentation mode" Test: Manual testing with additional logging Bug: 204105805 Bug: 182887411 Bug: 197790618 Change-Id: I9902d11aadf946a51c3f74e1462faf620a84a977 --- vulkan/libvulkan/swapchain.cpp | 62 ++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 41 deletions(-) diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 54b10b1127..b5a0bdfe6f 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -537,30 +537,6 @@ android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace) { } } -int get_min_buffer_count(ANativeWindow* window, - uint32_t* out_min_buffer_count) { - constexpr int kExtraBuffers = 2; - - int err; - int min_undequeued_buffers; - err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, - &min_undequeued_buffers); - if (err != android::OK || min_undequeued_buffers < 0) { - ALOGE( - "NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d) " - "value=%d", - strerror(-err), err, min_undequeued_buffers); - if (err == android::OK) { - err = android::UNKNOWN_ERROR; - } - return err; - } - - *out_min_buffer_count = - static_cast(min_undequeued_buffers + kExtraBuffers); - return android::OK; -} - } // anonymous namespace VKAPI_ATTR @@ -675,7 +651,7 @@ VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; } - capabilities->minImageCount = max_buffer_count == 1 ? 1 : 2; + capabilities->minImageCount = std::min(max_buffer_count, 3); capabilities->maxImageCount = static_cast(max_buffer_count); capabilities->currentExtent = @@ -877,13 +853,18 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, int err; int query_value; - uint32_t min_buffer_count; ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); - err = get_min_buffer_count(window, &min_buffer_count); - if (err != android::OK) { + err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, + &query_value); + if (err != android::OK || query_value < 0) { + ALOGE( + "NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d) " + "value=%d", + strerror(-err), err, query_value); return VK_ERROR_SURFACE_LOST_KHR; } + uint32_t min_undequeued_buffers = static_cast(query_value); err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value); if (err != android::OK || query_value < 0) { @@ -894,7 +875,7 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, uint32_t max_buffer_count = static_cast(query_value); std::vector present_modes; - if (min_buffer_count < max_buffer_count) + if (min_undequeued_buffers + 1 < max_buffer_count) present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR); present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR); @@ -1215,14 +1196,19 @@ VkResult CreateSwapchainKHR(VkDevice device, } } - uint32_t min_buffer_count; - err = get_min_buffer_count(window, &min_buffer_count); - if (err != android::OK) { + int query_value; + err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, + &query_value); + if (err != android::OK || query_value < 0) { + ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, + query_value); return VK_ERROR_SURFACE_LOST_KHR; } - - uint32_t num_images = - std::max(min_buffer_count, create_info->minImageCount); + uint32_t min_undequeued_buffers = static_cast(query_value); + const auto mailbox_num_images = std::max(3u, create_info->minImageCount); + const auto requested_images = + swap_interval ? create_info->minImageCount : mailbox_num_images; + uint32_t num_images = requested_images - 1 + min_undequeued_buffers; // Lower layer insists that we have at least two buffers. This is wasteful // and we'd like to relax it in the shared case, but not all the pieces are @@ -1236,12 +1222,6 @@ VkResult CreateSwapchainKHR(VkDevice device, return VK_ERROR_SURFACE_LOST_KHR; } - // In shared mode the num_images must be one regardless of how many - // buffers were allocated for the buffer queue. - if (swapchain_image_usage & VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID) { - num_images = 1; - } - int32_t legacy_usage = 0; if (dispatch.GetSwapchainGrallocUsage2ANDROID) { uint64_t consumer_usage, producer_usage; -- cgit v1.2.3-59-g8ed1b From 78c4a242236a3c4dd20227d4fbd4b4ade67ebca2 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 30 Nov 2021 17:49:44 -0800 Subject: SF: make RefreshRateOverlay a trusted overlay Bug: 207057942 Test: 1.Settings->System->Developper options->Show refresh rate,open 2.Open any app for the first time 3.click the prompt box of permission Change-Id: I06a3c3df7ca59b319a3906e83c7bb7e9f0f85d32 --- services/surfaceflinger/RefreshRateOverlay.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 712ab168a2..81c1566d71 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -203,12 +203,13 @@ bool RefreshRateOverlay::createLayer() { return false; } - SurfaceComposerClient::Transaction t; - t.setFrameRate(mSurfaceControl, 0.0f, - static_cast(Layer::FrameRateCompatibility::NoVote), - static_cast(scheduler::Seamlessness::OnlySeamless)); - t.setLayer(mSurfaceControl, INT32_MAX - 2); - t.apply(); + SurfaceComposerClient::Transaction() + .setFrameRate(mSurfaceControl, 0.0f, + static_cast(Layer::FrameRateCompatibility::NoVote), + static_cast(scheduler::Seamlessness::OnlySeamless)) + .setLayer(mSurfaceControl, INT32_MAX - 2) + .setTrustedOverlay(mSurfaceControl, true) + .apply(); return true; } -- cgit v1.2.3-59-g8ed1b From 923373d52068c901437599b5cfbbe7878f1d1a78 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Wed, 24 Nov 2021 15:36:43 +0000 Subject: Reland "Input injection: Assume transformed values are i..." Revert submission 16306432-revert-16295572-ORWQJPYRMQ Reason for revert: The broken test was fixed in ag/16365181, so this should be safe to re-land now. Reverted Changes: Iab395d41d:Revert "Remove x/y offset from MotionEntry" I7beca684d:Revert "Input injection: Assume transformed values... Change-Id: I68b5619bf52d999a653bb246e1acb02f5d07991e --- .../inputflinger/dispatcher/InputDispatcher.cpp | 55 ++++++++-------------- services/inputflinger/dispatcher/InputDispatcher.h | 4 +- .../inputflinger/tests/InputDispatcher_test.cpp | 27 +++++++++++ 3 files changed, 50 insertions(+), 36 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 7f68d1b8b1..3fd1c8aa27 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -506,12 +506,6 @@ bool isConnectionResponsive(const Connection& connection) { return true; } -vec2 transformWithoutTranslation(const ui::Transform& transform, float x, float y) { - const vec2 transformedXy = transform.transform(x, y); - const vec2 transformedOrigin = transform.transform(0, 0); - return transformedXy - transformedOrigin; -} - // Returns true if the event type passed as argument represents a user activity. bool isUserActivityEvent(const EventEntry& eventEntry) { switch (eventEntry.type) { @@ -4214,10 +4208,8 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawXCursorPosition(), motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), - pointerProperties, samplePointerCoords, - motionEvent.getXOffset(), - motionEvent.getYOffset()); - transformMotionEntryForInjectionLocked(*injectedEntry); + pointerProperties, samplePointerCoords, 0, 0); + transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(injectedEntry)); for (size_t i = motionEvent.getHistorySize(); i > 0; i--) { sampleEventTimes += 1; @@ -4236,9 +4228,9 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), pointerProperties, - samplePointerCoords, motionEvent.getXOffset(), - motionEvent.getYOffset()); - transformMotionEntryForInjectionLocked(*nextInjectedEntry); + samplePointerCoords, 0, 0); + transformMotionEntryForInjectionLocked(*nextInjectedEntry, + motionEvent.getTransform()); injectedEntries.push(std::move(nextInjectedEntry)); } break; @@ -4402,35 +4394,28 @@ void InputDispatcher::setInjectionResult(EventEntry& entry, } } -void InputDispatcher::transformMotionEntryForInjectionLocked(MotionEntry& entry) const { - const bool isRelativeMouseEvent = isFromSource(entry.source, AINPUT_SOURCE_MOUSE_RELATIVE); - if (!isRelativeMouseEvent && !isFromSource(entry.source, AINPUT_SOURCE_CLASS_POINTER)) { - return; - } - +void InputDispatcher::transformMotionEntryForInjectionLocked( + MotionEntry& entry, const ui::Transform& injectedTransform) const { // Input injection works in the logical display coordinate space, but the input pipeline works // display space, so we need to transform the injected events accordingly. const auto it = mDisplayInfos.find(entry.displayId); if (it == mDisplayInfos.end()) return; - const auto& transformToDisplay = it->second.transform.inverse(); + const auto& transformToDisplay = it->second.transform.inverse() * injectedTransform; for (uint32_t i = 0; i < entry.pointerCount; i++) { PointerCoords& pc = entry.pointerCoords[i]; - const auto xy = isRelativeMouseEvent - ? transformWithoutTranslation(transformToDisplay, pc.getX(), pc.getY()) - : transformToDisplay.transform(pc.getXYValue()); - pc.setAxisValue(AMOTION_EVENT_AXIS_X, xy.x); - pc.setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y); - - // Axes with relative values never represent points on a screen, so they should never have - // translation applied. If a device does not report relative values, these values are always - // 0, and will remain unaffected by the following operation. - const auto rel = - transformWithoutTranslation(transformToDisplay, - pc.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), - pc.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)); - pc.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, rel.x); - pc.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, rel.y); + // Make a copy of the injected coords. We cannot change them in place because some of them + // are interdependent (for example, X coordinate might depend on the Y coordinate). + PointerCoords injectedCoords = entry.pointerCoords[i]; + + BitSet64 bits(injectedCoords.bits); + while (!bits.isEmpty()) { + const auto axis = static_cast(bits.clearFirstMarkedBit()); + const float value = + MotionEvent::calculateTransformedAxisValue(axis, entry.source, + transformToDisplay, injectedCoords); + pc.setAxisValue(axis, value); + } } } diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 8a551cfca1..6f05670943 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -280,7 +280,9 @@ private: bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); void setInjectionResult(EventEntry& entry, android::os::InputEventInjectionResult injectionResult); - void transformMotionEntryForInjectionLocked(MotionEntry&) const REQUIRES(mLock); + void transformMotionEntryForInjectionLocked(MotionEntry&, + const ui::Transform& injectedTransform) const + REQUIRES(mLock); std::condition_variable mInjectionSyncFinished; void incrementPendingForegroundDispatches(EventEntry& entry); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 515a01e137..eaea4e26c4 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -2079,6 +2079,33 @@ TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) { secondWindow->assertNoEvents(); } +// Ensure that when a MotionEvent that has a custom transform is injected, the post-transformed +// event should be treated as being in the logical display space. +TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisplaySpace) { + auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); + + const std::array matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0}; + ui::Transform injectedEventTransform; + injectedEventTransform.set(matrix); + const vec2 expectedPoint{75, 55}; // The injected point in the logical display space. + const vec2 untransformedPoint = injectedEventTransform.inverse().transform(expectedPoint); + + MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(untransformedPoint.x) + .y(untransformedPoint.y)) + .build(); + event.transform(matrix); + + injectMotionEvent(mDispatcher, event, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT); + + firstWindow->consumeMotionDown(); + secondWindow->assertNoEvents(); +} + TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) { auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); -- cgit v1.2.3-59-g8ed1b From d6a7f22182d88888c6ac2824a888766203d33dfc Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Wed, 24 Nov 2021 15:36:43 +0000 Subject: Reland "Remove x/y offset from MotionEntry" 2b80b386c4ed5a1b3240da32080280b0a1ec9cef Change-Id: I5afb6f7fd25cd13e42a9b4368fa387bf574e5ec0 --- include/input/Input.h | 5 ++--- libs/input/Input.cpp | 5 ----- services/inputflinger/dispatcher/Entry.cpp | 5 +---- services/inputflinger/dispatcher/Entry.h | 3 +-- services/inputflinger/dispatcher/InputDispatcher.cpp | 10 +++++----- services/inputflinger/dispatcher/InputState.cpp | 6 ++---- 6 files changed, 11 insertions(+), 23 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index 1e06257591..1c79c4a21c 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -377,7 +377,6 @@ struct PointerCoords { // window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR // axes, however the window scaling will not. void scale(float globalScale, float windowXScale, float windowYScale); - void applyOffset(float xOffset, float yOffset); void transform(const ui::Transform& transform); @@ -567,7 +566,7 @@ public: inline float getYOffset() const { return mTransform.ty(); } - inline ui::Transform getTransform() const { return mTransform; } + inline const ui::Transform& getTransform() const { return mTransform; } inline float getXPrecision() const { return mXPrecision; } @@ -583,7 +582,7 @@ public: void setCursorPosition(float x, float y); - ui::Transform getRawTransform() const { return mRawTransform; } + inline const ui::Transform& getRawTransform() const { return mRawTransform; } static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); } diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 8974b22c86..69ea7dfcb5 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -343,11 +343,6 @@ void PointerCoords::scale(float globalScaleFactor, float windowXScale, float win scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_Y, windowYScale); } -void PointerCoords::applyOffset(float xOffset, float yOffset) { - setAxisValue(AMOTION_EVENT_AXIS_X, getX() + xOffset); - setAxisValue(AMOTION_EVENT_AXIS_Y, getY() + yOffset); -} - #ifdef __linux__ status_t PointerCoords::readFromParcel(Parcel* parcel) { bits = parcel->readInt64(); diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index 1674afd02e..3d0818b738 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -214,7 +214,7 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords, float xOffset, float yOffset) + const PointerCoords* pointerCoords) : EventEntry(id, Type::MOTION, eventTime, policyFlags), deviceId(deviceId), source(source), @@ -235,9 +235,6 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); this->pointerCoords[i].copyFrom(pointerCoords[i]); - if (xOffset || yOffset) { - this->pointerCoords[i].applyOffset(xOffset, yOffset); - } } } diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index 477781a2ad..0f792967eb 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -184,8 +184,7 @@ struct MotionEntry : EventEntry { int32_t metaState, int32_t buttonState, MotionClassification classification, int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xOffset, float yOffset); + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); std::string getDescription() const override; ~MotionEntry() override; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 3fd1c8aa27..04ff599f13 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -378,7 +378,7 @@ std::unique_ptr createDispatchEntry(const InputTarget& inputTarge motionEntry.yPrecision, motionEntry.xCursorPosition, motionEntry.yCursorPosition, motionEntry.downTime, motionEntry.pointerCount, motionEntry.pointerProperties, - pointerCoords.data(), 0 /* xOffset */, 0 /* yOffset */); + pointerCoords.data()); if (motionEntry.injectionState) { combinedMotionEntry->injectionState = motionEntry.injectionState; @@ -3752,7 +3752,7 @@ std::unique_ptr InputDispatcher::splitMotionEvent( originalMotionEntry.xCursorPosition, originalMotionEntry.yCursorPosition, originalMotionEntry.downTime, splitPointerCount, - splitPointerProperties, splitPointerCoords, 0, 0); + splitPointerProperties, splitPointerCoords); if (originalMotionEntry.injectionState) { splitMotionEntry->injectionState = originalMotionEntry.injectionState; @@ -3978,7 +3978,7 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { args->xPrecision, args->yPrecision, args->xCursorPosition, args->yCursorPosition, args->downTime, args->pointerCount, - args->pointerProperties, args->pointerCoords, 0, 0); + args->pointerProperties, args->pointerCoords); if (args->id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID && IdGenerator::getSource(args->id) == IdGenerator::Source::INPUT_READER && @@ -4208,7 +4208,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawXCursorPosition(), motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), - pointerProperties, samplePointerCoords, 0, 0); + pointerProperties, samplePointerCoords); transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(injectedEntry)); for (size_t i = motionEvent.getHistorySize(); i > 0; i--) { @@ -4228,7 +4228,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), pointerProperties, - samplePointerCoords, 0, 0); + samplePointerCoords); transformMotionEntryForInjectionLocked(*nextInjectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(nextInjectedEntry)); diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index 3bb0bc995c..ad3c6159ef 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -296,8 +296,7 @@ std::vector> InputState::synthesizeCancelationEvents memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, memento.pointerCount, memento.pointerProperties, - memento.pointerCoords, 0 /*xOffset*/, - 0 /*yOffset*/)); + memento.pointerCoords)); } } return events; @@ -349,8 +348,7 @@ std::vector> InputState::synthesizePointerDownEvents AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, - pointerCount, pointerProperties, pointerCoords, - 0 /*xOffset*/, 0 /*yOffset*/)); + pointerCount, pointerProperties, pointerCoords)); } memento.firstNewPointerIdx = INVALID_POINTER_INDEX; -- cgit v1.2.3-59-g8ed1b From 092f3a9b75b1fd465373730ca8d6038c89ed9220 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 25 Nov 2021 10:53:27 -0800 Subject: Add getSurfaceRotation API to MotionEvent Add an API to get the current rotation value of the transform of the MotionEvent. Bug: 207771136 Test: atest MotionEventTest Change-Id: I05fb4455d0dcfc0de8c8564473ee8d43ac86c0bd --- include/input/Input.h | 2 ++ libs/input/Input.cpp | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/include/input/Input.h b/include/input/Input.h index 5242dcb476..29503af65f 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -574,6 +574,8 @@ public: inline ui::Transform getTransform() const { return mTransform; } + int getSurfaceRotation() const; + inline float getXPrecision() const { return mXPrecision; } inline float getYPrecision() const { return mYPrecision; } diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index cb93c92310..44487c3a85 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -24,6 +24,7 @@ #include #include +#include (inputInfo.type)); + proto->set_layout_params_type(static_cast(inputInfo.layoutParamsType)); LayerProtoHelper::writeToProto({inputInfo.frameLeft, inputInfo.frameTop, inputInfo.frameRight, inputInfo.frameBottom}, @@ -189,9 +189,10 @@ void LayerProtoHelper::writeToProto( [&]() { return proto->mutable_touchable_region(); }); proto->set_surface_inset(inputInfo.surfaceInset); - proto->set_visible(inputInfo.visible); - proto->set_focusable(inputInfo.focusable); - proto->set_has_wallpaper(inputInfo.hasWallpaper); + using InputConfig = gui::WindowInfo::InputConfig; + proto->set_visible(!inputInfo.inputConfig.test(InputConfig::NOT_VISIBLE)); + proto->set_focusable(!inputInfo.inputConfig.test(InputConfig::NOT_FOCUSABLE)); + proto->set_has_wallpaper(inputInfo.inputConfig.test(InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)); proto->set_global_scale_factor(inputInfo.globalScaleFactor); LayerProtoHelper::writeToProtoDeprecated(inputInfo.transform, proto->mutable_transform()); diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp index a91698fb79..c736d05506 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp @@ -183,13 +183,16 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer, if (layer.windowInfoHandle) { const gui::WindowInfo* inputInfo = layer.windowInfoHandle->getInfo(); proto::LayerState_WindowInfo* windowInfoProto = proto.mutable_window_info_handle(); - windowInfoProto->set_layout_params_flags(inputInfo->flags.get()); - windowInfoProto->set_layout_params_type(static_cast(inputInfo->type)); + windowInfoProto->set_layout_params_flags(inputInfo->layoutParamsFlags.get()); + windowInfoProto->set_layout_params_type( + static_cast(inputInfo->layoutParamsType)); LayerProtoHelper::writeToProto(inputInfo->touchableRegion, windowInfoProto->mutable_touchable_region()); windowInfoProto->set_surface_inset(inputInfo->surfaceInset); - windowInfoProto->set_focusable(inputInfo->focusable); - windowInfoProto->set_has_wallpaper(inputInfo->hasWallpaper); + windowInfoProto->set_focusable( + !inputInfo->inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE)); + windowInfoProto->set_has_wallpaper(inputInfo->inputConfig.test( + gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)); windowInfoProto->set_global_scale_factor(inputInfo->globalScaleFactor); proto::LayerState_Transform* transformProto = windowInfoProto->mutable_transform(); transformProto->set_dsdx(inputInfo->transform.dsdx()); @@ -471,13 +474,17 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, gui::WindowInfo inputInfo; const proto::LayerState_WindowInfo& windowInfoProto = proto.window_info_handle(); - inputInfo.flags = static_cast(windowInfoProto.layout_params_flags()); - inputInfo.type = static_cast(windowInfoProto.layout_params_type()); + inputInfo.layoutParamsFlags = + static_cast(windowInfoProto.layout_params_flags()); + inputInfo.layoutParamsType = + static_cast(windowInfoProto.layout_params_type()); LayerProtoHelper::readFromProto(windowInfoProto.touchable_region(), inputInfo.touchableRegion); inputInfo.surfaceInset = windowInfoProto.surface_inset(); - inputInfo.focusable = windowInfoProto.focusable(); - inputInfo.hasWallpaper = windowInfoProto.has_wallpaper(); + inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_FOCUSABLE, + !windowInfoProto.focusable()); + inputInfo.setInputConfig(gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER, + windowInfoProto.has_wallpaper()); inputInfo.globalScaleFactor = windowInfoProto.global_scale_factor(); const proto::LayerState_Transform& transformProto = windowInfoProto.transform(); inputInfo.transform.set(transformProto.dsdx(), transformProto.dtdx(), transformProto.dtdy(), -- cgit v1.2.3-59-g8ed1b From f0a3d814ee6e01b0dd398a9df4af462eb91d0b59 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Mon, 7 Feb 2022 02:54:39 -0800 Subject: ftl::Flags: Offer set and clear APIs for convenience and readability Bug: None Test: None Change-Id: Idbe075dd919fd71bdcb7b1fb4a182c44d243b378 --- include/ftl/Flags.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/ftl/Flags.h b/include/ftl/Flags.h index 932af2d9f9..708eaf5dde 100644 --- a/include/ftl/Flags.h +++ b/include/ftl/Flags.h @@ -120,10 +120,10 @@ public: } /* Tests whether any of the given flags are set */ - bool any(Flags f) { return (mFlags & f.mFlags) != 0; } + bool any(Flags f) const { return (mFlags & f.mFlags) != 0; } /* Tests whether all of the given flags are set */ - bool all(Flags f) { return (mFlags & f.mFlags) == f.mFlags; } + bool all(Flags f) const { return (mFlags & f.mFlags) == f.mFlags; } Flags operator|(Flags rhs) const { return static_cast(mFlags | rhs.mFlags); } Flags& operator|=(Flags rhs) { @@ -153,6 +153,10 @@ public: return *this; } + inline Flags& clear(Flags f = static_cast(~static_cast(0))) { + return *this &= ~f; + } + Iterator begin() const { return Iterator(*this); } Iterator end() const { return Iterator(); } -- cgit v1.2.3-59-g8ed1b From 685cfefb624ec9414cf3c1bb2de1f8fbadefc0dd Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Wed, 2 Feb 2022 10:01:25 -0800 Subject: TransactionTracing: Introduce FlingerDataMapper Allow the proto parser to handle dependencies that are external to layer via a clear interface. This is needed to make sure the parser can map handles to ids, get buffer info from cached buffers or inject fake buffers in transactions to recreate the layer's internal state. Test: presubmit Bug: 200284593 Change-Id: I830048a560945cce088d7276e764c953f408e0d3 --- libs/gui/LayerState.cpp | 24 +++-- .../Tracing/TransactionProtoParser.cpp | 108 ++++++++++----------- .../Tracing/TransactionProtoParser.h | 84 ++++++++++++---- .../surfaceflinger/Tracing/TransactionTracing.cpp | 80 ++++++++++----- .../surfaceflinger/Tracing/TransactionTracing.h | 1 + .../tests/unittests/TransactionProtoParserTest.cpp | 39 +++++--- .../tests/unittests/TransactionTracingTest.cpp | 4 +- 7 files changed, 215 insertions(+), 125 deletions(-) diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index eec4a874b9..9022e7d5a4 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -35,7 +35,9 @@ using gui::FocusRequest; using gui::WindowInfoHandle; layer_state_t::layer_state_t() - : what(0), + : surface(nullptr), + layerId(-1), + what(0), x(0), y(0), z(0), @@ -153,8 +155,12 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeBool, isTrustedOverlay); SAFE_PARCEL(output.writeUint32, static_cast(dropInputMode)); - SAFE_PARCEL(output.writeNullableParcelable, - bufferData ? std::make_optional(*bufferData) : std::nullopt); + + const bool hasBufferData = (bufferData != nullptr); + SAFE_PARCEL(output.writeBool, hasBufferData); + if (hasBufferData) { + SAFE_PARCEL(output.writeParcelable, *bufferData); + } return NO_ERROR; } @@ -264,9 +270,15 @@ status_t layer_state_t::read(const Parcel& input) uint32_t mode; SAFE_PARCEL(input.readUint32, &mode); dropInputMode = static_cast(mode); - std::optional tmpBufferData; - SAFE_PARCEL(input.readParcelable, &tmpBufferData); - bufferData = tmpBufferData ? std::make_shared(*tmpBufferData) : nullptr; + + bool hasBufferData; + SAFE_PARCEL(input.readBool, &hasBufferData); + if (hasBufferData) { + bufferData = std::make_shared(); + SAFE_PARCEL(input.readParcelable, bufferData.get()); + } else { + bufferData = nullptr; + } return NO_ERROR; } diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp index a91698fb79..fb5a6b3eb7 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp @@ -22,9 +22,7 @@ namespace android::surfaceflinger { -proto::TransactionState TransactionProtoParser::toProto(const TransactionState& t, - LayerHandleToIdFn getLayerId, - DisplayHandleToIdFn getDisplayId) { +proto::TransactionState TransactionProtoParser::toProto(const TransactionState& t) { proto::TransactionState proto; proto.set_pid(t.originPid); proto.set_uid(t.originUid); @@ -33,12 +31,14 @@ proto::TransactionState TransactionProtoParser::toProto(const TransactionState& proto.set_post_time(t.postTime); proto.set_transaction_id(t.id); + proto.mutable_layer_changes()->Reserve(static_cast(t.states.size())); for (auto& layerState : t.states) { - proto.mutable_layer_changes()->Add(std::move(toProto(layerState.state, getLayerId))); + proto.mutable_layer_changes()->Add(std::move(toProto(layerState.state))); } + proto.mutable_display_changes()->Reserve(static_cast(t.displays.size())); for (auto& displayState : t.displays) { - proto.mutable_display_changes()->Add(std::move(toProto(displayState, getDisplayId))); + proto.mutable_display_changes()->Add(std::move(toProto(displayState))); } return proto; } @@ -46,8 +46,9 @@ proto::TransactionState TransactionProtoParser::toProto(const TransactionState& proto::TransactionState TransactionProtoParser::toProto( const std::map& states) { proto::TransactionState proto; + proto.mutable_layer_changes()->Reserve(static_cast(states.size())); for (auto& [layerId, state] : states) { - proto::LayerState layerProto = toProto(state, nullptr); + proto::LayerState layerProto = toProto(state); if (layerProto.has_buffer_data()) { proto::LayerState_BufferData* bufferProto = layerProto.mutable_buffer_data(); bufferProto->set_buffer_id(state.bufferId); @@ -69,11 +70,10 @@ proto::TransactionState TransactionProtoParser::toProto( return proto; } -proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer, - LayerHandleToIdFn getLayerId) { +proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer) { proto::LayerState proto; - if (getLayerId != nullptr) { - proto.set_layer_id(getLayerId(layer.surface)); + if (layer.surface) { + proto.set_layer_id(mMapper->getLayerId(layer.surface)); } else { proto.set_layer_id(layer.layerId); } @@ -136,13 +136,27 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer, } if (layer.what & layer_state_t::eBufferChanged) { proto::LayerState_BufferData* bufferProto = proto.mutable_buffer_data(); - if (layer.bufferData->buffer) { + if (layer.bufferData->hasBuffer()) { bufferProto->set_buffer_id(layer.bufferData->getId()); bufferProto->set_width(layer.bufferData->getWidth()); bufferProto->set_height(layer.bufferData->getHeight()); bufferProto->set_pixel_format(static_cast( layer.bufferData->getPixelFormat())); bufferProto->set_usage(layer.bufferData->getUsage()); + } else { + uint64_t bufferId; + uint32_t width; + uint32_t height; + int32_t pixelFormat; + uint64_t usage; + mMapper->getGraphicBufferPropertiesFromCache(layer.bufferData->cachedBuffer, &bufferId, + &width, &height, &pixelFormat, &usage); + bufferProto->set_buffer_id(bufferId); + bufferProto->set_width(width); + bufferProto->set_height(height); + bufferProto->set_pixel_format( + static_cast(pixelFormat)); + bufferProto->set_usage(usage); } bufferProto->set_frame_number(layer.bufferData->frameNumber); bufferProto->set_flags(layer.bufferData->flags.get()); @@ -165,15 +179,15 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer, } } - if ((layer.what & layer_state_t::eReparent) && getLayerId != nullptr) { + if (layer.what & layer_state_t::eReparent) { int32_t layerId = layer.parentSurfaceControlForChild - ? getLayerId(layer.parentSurfaceControlForChild->getHandle()) + ? mMapper->getLayerId(layer.parentSurfaceControlForChild->getHandle()) : -1; proto.set_parent_id(layerId); } - if ((layer.what & layer_state_t::eRelativeLayerChanged) && getLayerId != nullptr) { + if (layer.what & layer_state_t::eRelativeLayerChanged) { int32_t layerId = layer.relativeLayerSurfaceControl - ? getLayerId(layer.relativeLayerSurfaceControl->getHandle()) + ? mMapper->getLayerId(layer.relativeLayerSurfaceControl->getHandle()) : -1; proto.set_relative_parent_id(layerId); proto.set_z(layer.z); @@ -200,12 +214,8 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer, transformProto->set_ty(inputInfo->transform.ty()); windowInfoProto->set_replace_touchable_region_with_crop( inputInfo->replaceTouchableRegionWithCrop); - if (getLayerId != nullptr) { - windowInfoProto->set_crop_layer_id( - getLayerId(inputInfo->touchableRegionCropHandle.promote())); - } else { - windowInfoProto->set_crop_layer_id(-1); - } + windowInfoProto->set_crop_layer_id( + mMapper->getLayerId(inputInfo->touchableRegionCropHandle.promote())); } } if (layer.what & layer_state_t::eBackgroundColorChanged) { @@ -252,13 +262,10 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer, return proto; } -proto::DisplayState TransactionProtoParser::toProto(const DisplayState& display, - DisplayHandleToIdFn getDisplayId) { +proto::DisplayState TransactionProtoParser::toProto(const DisplayState& display) { proto::DisplayState proto; proto.set_what(display.what); - if (getDisplayId != nullptr) { - proto.set_id(getDisplayId(display.token)); - } + proto.set_id(mMapper->getDisplayId(display.token)); if (display.what & DisplayState::eLayerStackChanged) { proto.set_layer_stack(display.layerStack.id); @@ -290,9 +297,7 @@ proto::LayerCreationArgs TransactionProtoParser::toProto(const TracingLayerCreat return proto; } -TransactionState TransactionProtoParser::fromProto(const proto::TransactionState& proto, - LayerIdToHandleFn getLayerHandle, - DisplayIdToHandleFn getDisplayHandle) { +TransactionState TransactionProtoParser::fromProto(const proto::TransactionState& proto) { TransactionState t; t.originPid = proto.pid(); t.originUid = proto.uid(); @@ -306,14 +311,14 @@ TransactionState TransactionProtoParser::fromProto(const proto::TransactionState for (int i = 0; i < layerCount; i++) { ComposerState s; s.state.what = 0; - fromProto(proto.layer_changes(i), getLayerHandle, s.state); + fromProto(proto.layer_changes(i), s.state); t.states.add(s); } int32_t displayCount = proto.display_changes_size(); t.displays.reserve(static_cast(displayCount)); for (int i = 0; i < displayCount; i++) { - t.displays.add(fromProto(proto.display_changes(i), getDisplayHandle)); + t.displays.add(fromProto(proto.display_changes(i))); } return t; } @@ -328,10 +333,9 @@ void TransactionProtoParser::fromProto(const proto::LayerCreationArgs& proto, } void TransactionProtoParser::mergeFromProto(const proto::LayerState& proto, - LayerIdToHandleFn getLayerHandle, TracingLayerState& outState) { layer_state_t state; - fromProto(proto, getLayerHandle, state); + fromProto(proto, state); outState.merge(state); if (state.what & layer_state_t::eReparent) { @@ -356,14 +360,10 @@ void TransactionProtoParser::mergeFromProto(const proto::LayerState& proto, } } -void TransactionProtoParser::fromProto(const proto::LayerState& proto, - LayerIdToHandleFn getLayerHandle, layer_state_t& layer) { +void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_state_t& layer) { layer.layerId = proto.layer_id(); layer.what |= proto.what(); - - if (getLayerHandle != nullptr) { - layer.surface = getLayerHandle(layer.layerId); - } + layer.surface = mMapper->getLayerHandle(layer.layerId); if (proto.what() & layer_state_t::ePositionChanged) { layer.x = proto.x(); @@ -420,10 +420,11 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, LayerProtoHelper::readFromProto(proto.crop(), layer.crop); } if (proto.what() & layer_state_t::eBufferChanged) { - if (!layer.bufferData) { - layer.bufferData = std::make_shared(); - } const proto::LayerState_BufferData& bufferProto = proto.buffer_data(); + layer.bufferData = + std::move(mMapper->getGraphicData(bufferProto.buffer_id(), bufferProto.width(), + bufferProto.height(), bufferProto.pixel_format(), + bufferProto.usage())); layer.bufferData->frameNumber = bufferProto.frame_number(); layer.bufferData->flags = Flags(bufferProto.flags()); layer.bufferData->cachedBuffer.id = bufferProto.cached_buffer_id(); @@ -445,24 +446,24 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, } } - if ((proto.what() & layer_state_t::eReparent) && (getLayerHandle != nullptr)) { + if (proto.what() & layer_state_t::eReparent) { int32_t layerId = proto.parent_id(); if (layerId == -1) { layer.parentSurfaceControlForChild = nullptr; } else { layer.parentSurfaceControlForChild = - new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId), - nullptr, layerId); + new SurfaceControl(SurfaceComposerClient::getDefault(), + mMapper->getLayerHandle(layerId), nullptr, layerId); } } if (proto.what() & layer_state_t::eRelativeLayerChanged) { int32_t layerId = proto.relative_parent_id(); if (layerId == -1) { layer.relativeLayerSurfaceControl = nullptr; - } else if (getLayerHandle != nullptr) { + } else { layer.relativeLayerSurfaceControl = - new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId), - nullptr, layerId); + new SurfaceControl(SurfaceComposerClient::getDefault(), + mMapper->getLayerHandle(layerId), nullptr, layerId); } layer.z = proto.z(); } @@ -486,9 +487,7 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, inputInfo.replaceTouchableRegionWithCrop = windowInfoProto.replace_touchable_region_with_crop(); int32_t layerId = windowInfoProto.crop_layer_id(); - if (getLayerHandle != nullptr) { - inputInfo.touchableRegionCropHandle = getLayerHandle(layerId); - } + inputInfo.touchableRegionCropHandle = mMapper->getLayerHandle(layerId); layer.windowInfoHandle = sp::make(inputInfo); } if (proto.what() & layer_state_t::eBackgroundColorChanged) { @@ -534,13 +533,10 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, } } -DisplayState TransactionProtoParser::fromProto(const proto::DisplayState& proto, - DisplayIdToHandleFn getDisplayHandle) { +DisplayState TransactionProtoParser::fromProto(const proto::DisplayState& proto) { DisplayState display; display.what = proto.what(); - if (getDisplayHandle != nullptr) { - display.token = getDisplayHandle(proto.id()); - } + display.token = mMapper->getDisplayHandle(proto.id()); if (display.what & DisplayState::eLayerStackChanged) { display.layerStack.id = proto.layer_stack(); diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h index d589936642..2f70b27bf6 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.h +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h @@ -43,33 +43,77 @@ struct TracingLayerState : layer_state_t { TracingLayerCreationArgs args; }; +// Class which exposes buffer properties from BufferData without holding on to the actual buffer +// handle. +class BufferDataStub : public BufferData { +public: + BufferDataStub(uint64_t bufferId, uint32_t width, uint32_t height, int32_t pixelFormat, + uint64_t outUsage) + : mBufferId(bufferId), + mWidth(width), + mHeight(height), + mPixelFormat(pixelFormat), + mOutUsage(outUsage) {} + bool hasBuffer() const override { return mBufferId != 0; } + bool hasSameBuffer(const BufferData& other) const override { + return getId() == other.getId() && frameNumber == other.frameNumber; + } + uint32_t getWidth() const override { return mWidth; } + uint32_t getHeight() const override { return mHeight; } + uint64_t getId() const override { return mBufferId; } + PixelFormat getPixelFormat() const override { return mPixelFormat; } + uint64_t getUsage() const override { return mOutUsage; } + +private: + uint64_t mBufferId; + uint32_t mWidth; + uint32_t mHeight; + int32_t mPixelFormat; + uint64_t mOutUsage; +}; + class TransactionProtoParser { public: - typedef std::function(int32_t)> LayerIdToHandleFn; - typedef std::function(int32_t)> DisplayIdToHandleFn; - typedef std::function&)> LayerHandleToIdFn; - typedef std::function&)> DisplayHandleToIdFn; + // Utility class to map handles to ids and buffers to buffer properties without pulling + // in SurfaceFlinger dependencies. + class FlingerDataMapper { + public: + virtual ~FlingerDataMapper() = default; + virtual sp getLayerHandle(int32_t /* layerId */) const { return nullptr; } + virtual int32_t getLayerId(const sp& /* layerHandle */) const { return -1; } + virtual sp getDisplayHandle(int32_t /* displayId */) const { return nullptr; } + virtual int32_t getDisplayId(const sp& /* displayHandle */) const { return -1; } + virtual std::shared_ptr getGraphicData(uint64_t bufferId, uint32_t width, + uint32_t height, int32_t pixelFormat, + uint64_t usage) const { + return std::make_shared(bufferId, width, height, pixelFormat, usage); + } + virtual void getGraphicBufferPropertiesFromCache(client_cache_t /* cachedBuffer */, + uint64_t* /* outBufferId */, + uint32_t* /* outWidth */, + uint32_t* /* outHeight */, + int32_t* /* outPixelFormat */, + uint64_t* /* outUsage */) const {} + }; - static proto::TransactionState toProto(const TransactionState&, LayerHandleToIdFn getLayerIdFn, - DisplayHandleToIdFn getDisplayIdFn); - static proto::TransactionState toProto( - const std::map&); + TransactionProtoParser(std::unique_ptr provider) + : mMapper(std::move(provider)) {} - static proto::LayerCreationArgs toProto(const TracingLayerCreationArgs& args); + proto::TransactionState toProto(const TransactionState&); + proto::TransactionState toProto(const std::map&); + proto::LayerCreationArgs toProto(const TracingLayerCreationArgs& args); - static TransactionState fromProto(const proto::TransactionState&, - LayerIdToHandleFn getLayerHandleFn, - DisplayIdToHandleFn getDisplayHandleFn); - static void mergeFromProto(const proto::LayerState&, LayerIdToHandleFn getLayerHandleFn, - TracingLayerState& outState); - static void fromProto(const proto::LayerCreationArgs&, TracingLayerCreationArgs& outArgs); + TransactionState fromProto(const proto::TransactionState&); + void mergeFromProto(const proto::LayerState&, TracingLayerState& outState); + void fromProto(const proto::LayerCreationArgs&, TracingLayerCreationArgs& outArgs); private: - static proto::LayerState toProto(const layer_state_t&, LayerHandleToIdFn getLayerId); - static proto::DisplayState toProto(const DisplayState&, DisplayHandleToIdFn getDisplayId); - static void fromProto(const proto::LayerState&, LayerIdToHandleFn getLayerHandle, - layer_state_t& out); - static DisplayState fromProto(const proto::DisplayState&, DisplayIdToHandleFn getDisplayHandle); + proto::LayerState toProto(const layer_state_t&); + proto::DisplayState toProto(const DisplayState&); + void fromProto(const proto::LayerState&, layer_state_t& out); + DisplayState fromProto(const proto::DisplayState&); + + std::unique_ptr mMapper; }; } // namespace android::surfaceflinger diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp index a46b79578f..298e63ab67 100644 --- a/services/surfaceflinger/Tracing/TransactionTracing.cpp +++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp @@ -23,11 +23,57 @@ #include #include +#include "ClientCache.h" #include "TransactionTracing.h" +#include "renderengine/ExternalTexture.h" namespace android { -TransactionTracing::TransactionTracing() { +class FlingerDataMapper : public TransactionProtoParser::FlingerDataMapper { + std::unordered_map& mLayerHandles; + +public: + FlingerDataMapper(std::unordered_map& layerHandles) + : mLayerHandles(layerHandles) {} + + int32_t getLayerId(const sp& layerHandle) const override { + if (layerHandle == nullptr) { + return -1; + } + auto it = mLayerHandles.find(layerHandle->localBinder()); + if (it == mLayerHandles.end()) { + ALOGW("Could not find layer handle %p", layerHandle->localBinder()); + return -1; + } + return it->second; + } + + void getGraphicBufferPropertiesFromCache(client_cache_t cachedBuffer, uint64_t* outBufferId, + uint32_t* outWidth, uint32_t* outHeight, + int32_t* outPixelFormat, + uint64_t* outUsage) const override { + std::shared_ptr buffer = + ClientCache::getInstance().get(cachedBuffer); + if (!buffer || !buffer->getBuffer()) { + *outBufferId = 0; + *outWidth = 0; + *outHeight = 0; + *outPixelFormat = 0; + *outUsage = 0; + return; + } + + *outBufferId = buffer->getId(); + *outWidth = buffer->getWidth(); + *outHeight = buffer->getHeight(); + *outPixelFormat = buffer->getPixelFormat(); + *outUsage = buffer->getUsage(); + return; + } +}; + +TransactionTracing::TransactionTracing() + : mProtoParser(std::make_unique(mLayerHandles)) { std::scoped_lock lock(mTraceLock); mBuffer.setSize(mBufferSizeInBytes); @@ -85,11 +131,7 @@ void TransactionTracing::dump(std::string& result) const { void TransactionTracing::addQueuedTransaction(const TransactionState& transaction) { std::scoped_lock lock(mTraceLock); ATRACE_CALL(); - mQueuedTransactions[transaction.id] = - TransactionProtoParser::toProto(transaction, - std::bind(&TransactionTracing::getLayerIdLocked, this, - std::placeholders::_1), - nullptr); + mQueuedTransactions[transaction.id] = mProtoParser.toProto(transaction); } void TransactionTracing::addCommittedTransactions(std::vector& transactions, @@ -212,9 +254,7 @@ void TransactionTracing::onLayerAdded(BBinder* layerHandle, int layerId, const s ALOGW("Duplicate handles found. %p", layerHandle); } mLayerHandles[layerHandle] = layerId; - proto::LayerCreationArgs protoArgs = TransactionProtoParser::toProto(args); - proto::LayerCreationArgs protoArgsCopy = protoArgs; - mCreatedLayers.push_back(protoArgs); + mCreatedLayers.push_back(mProtoParser.toProto(args)); } void TransactionTracing::onMirrorLayerAdded(BBinder* layerHandle, int layerId, @@ -225,7 +265,7 @@ void TransactionTracing::onMirrorLayerAdded(BBinder* layerHandle, int layerId, ALOGW("Duplicate handles found. %p", layerHandle); } mLayerHandles[layerHandle] = layerId; - mCreatedLayers.emplace_back(TransactionProtoParser::toProto(args)); + mCreatedLayers.emplace_back(mProtoParser.toProto(args)); } void TransactionTracing::onLayerRemoved(int32_t layerId) { @@ -263,18 +303,6 @@ void TransactionTracing::tryPushToTracingThread() { } } -int32_t TransactionTracing::getLayerIdLocked(const sp& layerHandle) { - if (layerHandle == nullptr) { - return -1; - } - auto it = mLayerHandles.find(layerHandle->localBinder()); - if (it == mLayerHandles.end()) { - ALOGW("Could not find layer handle %p", layerHandle->localBinder()); - return -1; - } - return it->second; -} - void TransactionTracing::updateStartingStateLocked( const proto::TransactionTraceEntry& removedEntry) { mStartingTimestamp = removedEntry.elapsed_realtime_nanos(); @@ -283,7 +311,7 @@ void TransactionTracing::updateStartingStateLocked( for (const proto::LayerCreationArgs& addedLayer : removedEntry.added_layers()) { TracingLayerState& startingState = mStartingStates[addedLayer.layer_id()]; startingState.layerId = addedLayer.layer_id(); - TransactionProtoParser::fromProto(addedLayer, startingState.args); + mProtoParser.fromProto(addedLayer, startingState.args); } // Merge layer states to starting transaction state. @@ -294,7 +322,7 @@ void TransactionTracing::updateStartingStateLocked( ALOGW("Could not find layer id %d", layerState.layer_id()); continue; } - TransactionProtoParser::mergeFromProto(layerState, nullptr, it->second); + mProtoParser.mergeFromProto(layerState, it->second); } } @@ -316,10 +344,10 @@ void TransactionTracing::addStartingStateToProtoLocked(proto::TransactionTraceFi entryProto->mutable_added_layers()->Reserve(static_cast(mStartingStates.size())); for (auto& [layerId, state] : mStartingStates) { - entryProto->mutable_added_layers()->Add(TransactionProtoParser::toProto(state.args)); + entryProto->mutable_added_layers()->Add(mProtoParser.toProto(state.args)); } - proto::TransactionState transactionProto = TransactionProtoParser::toProto(mStartingStates); + proto::TransactionState transactionProto = mProtoParser.toProto(mStartingStates); transactionProto.set_vsync_id(0); transactionProto.set_post_time(mStartingTimestamp); entryProto->mutable_transactions()->Add(std::move(transactionProto)); diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h index d5d98cee9d..c20f22a94b 100644 --- a/services/surfaceflinger/Tracing/TransactionTracing.h +++ b/services/surfaceflinger/Tracing/TransactionTracing.h @@ -84,6 +84,7 @@ private: GUARDED_BY(mTraceLock); std::vector mRemovedLayerHandles GUARDED_BY(mTraceLock); std::map mStartingStates GUARDED_BY(mTraceLock); + TransactionProtoParser mProtoParser GUARDED_BY(mTraceLock); // We do not want main thread to block so main thread will try to acquire mMainThreadLock, // otherwise will push data to temporary container. diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp index 271b1c0211..ab893a3058 100644 --- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp @@ -70,23 +70,32 @@ TEST(TransactionProtoParserTest, parse) { t1.displays.add(display); } - TransactionProtoParser::LayerHandleToIdFn getLayerIdFn = [&](const sp& handle) { - return (handle == layerHandle) ? 42 : -1; - }; - TransactionProtoParser::DisplayHandleToIdFn getDisplayIdFn = [&](const sp& handle) { - return (handle == displayHandle) ? 43 : -1; - }; - TransactionProtoParser::LayerIdToHandleFn getLayerHandleFn = [&](int32_t id) { - return (id == 42) ? layerHandle : nullptr; - }; - TransactionProtoParser::DisplayIdToHandleFn getDisplayHandleFn = [&](int32_t id) { - return (id == 43) ? displayHandle : nullptr; + class TestMapper : public TransactionProtoParser::FlingerDataMapper { + public: + sp layerHandle; + sp displayHandle; + + TestMapper(sp layerHandle, sp displayHandle) + : layerHandle(layerHandle), displayHandle(displayHandle) {} + + sp getLayerHandle(int32_t id) const override { + return (id == 42) ? layerHandle : nullptr; + } + int32_t getLayerId(const sp& handle) const override { + return (handle == layerHandle) ? 42 : -1; + } + sp getDisplayHandle(int32_t id) const { + return (id == 43) ? displayHandle : nullptr; + } + int32_t getDisplayId(const sp& handle) const { + return (handle == displayHandle) ? 43 : -1; + } }; - proto::TransactionState proto = - TransactionProtoParser::toProto(t1, getLayerIdFn, getDisplayIdFn); - TransactionState t2 = - TransactionProtoParser::fromProto(proto, getLayerHandleFn, getDisplayHandleFn); + TransactionProtoParser parser(std::make_unique(layerHandle, displayHandle)); + + proto::TransactionState proto = parser.toProto(t1); + TransactionState t2 = parser.fromProto(proto); ASSERT_EQ(t1.originPid, t2.originPid); ASSERT_EQ(t1.originUid, t2.originUid); diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp index 39dbb07653..61b72a0b9b 100644 --- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp @@ -178,8 +178,8 @@ TEST_F(TransactionTracingLayerHandlingTest, addStartingState) { // verify we can still retrieve the layer change from the first entry containing starting // states. EXPECT_GT(proto.entry().size(), 0); - EXPECT_GT(proto.entry(0).transactions().size(), 0); - EXPECT_GT(proto.entry(0).added_layers().size(), 0); + EXPECT_EQ(proto.entry(0).transactions().size(), 1); + EXPECT_EQ(proto.entry(0).added_layers().size(), 2); EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 2); EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).layer_id(), mParentLayerId); EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).z(), 42); -- cgit v1.2.3-59-g8ed1b From d8f5e9fedc217ca9c257599b2c624b260b6852d6 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 3 Feb 2022 10:23:28 -0800 Subject: SF: Save proto traces to a specific path Test: presubmit Bug: 200284593 Change-Id: I6987329cc32b2ca13e76e957a5ae6b17bbed6e83 --- services/surfaceflinger/Layer.cpp | 18 ++++++++---------- services/surfaceflinger/Layer.h | 4 ++-- services/surfaceflinger/LayerProtoHelper.cpp | 12 ++++++------ services/surfaceflinger/SurfaceFlinger.cpp | 22 +++++++++------------- services/surfaceflinger/SurfaceFlinger.h | 5 +++++ services/surfaceflinger/Tracing/LayerTracing.cpp | 4 ++-- services/surfaceflinger/Tracing/LayerTracing.h | 2 +- services/surfaceflinger/Tracing/RingBuffer.h | 2 +- .../surfaceflinger/Tracing/TransactionTracing.cpp | 4 ++-- .../surfaceflinger/Tracing/TransactionTracing.h | 2 +- 10 files changed, 37 insertions(+), 38 deletions(-) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index a039250327..973029cb19 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1993,29 +1993,31 @@ void Layer::setInputInfo(const WindowInfo& info) { setTransactionFlags(eTransactionNeeded); } -LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags, - const DisplayDevice* display) { +LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags) { LayerProto* layerProto = layersProto.add_layers(); - writeToProtoDrawingState(layerProto, traceFlags, display); + writeToProtoDrawingState(layerProto); writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags); if (traceFlags & LayerTracing::TRACE_COMPOSITION) { // Only populate for the primary display. + UnnecessaryLock assumeLocked(mFlinger->mStateLock); // called from the main thread. + const auto display = mFlinger->getDefaultDisplayDeviceLocked(); if (display) { const auto compositionType = getCompositionType(*display); layerProto->set_hwc_composition_type(static_cast(compositionType)); + LayerProtoHelper::writeToProto(getVisibleRegion(display.get()), + [&]() { return layerProto->mutable_visible_region(); }); } } for (const sp& layer : mDrawingChildren) { - layer->writeToProto(layersProto, traceFlags, display); + layer->writeToProto(layersProto, traceFlags); } return layerProto; } -void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, - const DisplayDevice* display) { +void Layer::writeToProtoDrawingState(LayerProto* layerInfo) { const ui::Transform transform = getTransform(); auto buffer = getExternalTexture(); if (buffer != nullptr) { @@ -2039,10 +2041,6 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(), [&]() { return layerInfo->mutable_position(); }); LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); }); - if (traceFlags & LayerTracing::TRACE_COMPOSITION) { - LayerProtoHelper::writeToProto(getVisibleRegion(display), - [&]() { return layerInfo->mutable_visible_region(); }); - } LayerProtoHelper::writeToProto(surfaceDamageRegion, [&]() { return layerInfo->mutable_damage_region(); }); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index e51af1e10e..21dd5f4954 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -686,12 +686,12 @@ public: bool isRemovedFromCurrentState() const; - LayerProto* writeToProto(LayersProto& layersProto, uint32_t traceFlags, const DisplayDevice*); + LayerProto* writeToProto(LayersProto& layersProto, uint32_t traceFlags); // Write states that are modified by the main thread. This includes drawing // state as well as buffer data. This should be called in the main or tracing // thread. - void writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, const DisplayDevice*); + void writeToProtoDrawingState(LayerProto* layerInfo); // Write drawing or current state. If writing current state, the caller should hold the // external mStateLock. If writing drawing state, this function should be called on the // main or tracing thread. diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp index 015caa6a9b..3bd0643a6d 100644 --- a/services/surfaceflinger/LayerProtoHelper.cpp +++ b/services/surfaceflinger/LayerProtoHelper.cpp @@ -156,14 +156,14 @@ void LayerProtoHelper::writeTransformToProto(const ui::Transform& transform, void LayerProtoHelper::writeToProto(const renderengine::ExternalTexture& buffer, std::function getActiveBufferProto) { - if (buffer.getBuffer()->getWidth() != 0 || buffer.getBuffer()->getHeight() != 0 || - buffer.getBuffer()->getUsage() != 0 || buffer.getBuffer()->getPixelFormat() != 0) { + if (buffer.getWidth() != 0 || buffer.getHeight() != 0 || buffer.getUsage() != 0 || + buffer.getPixelFormat() != 0) { // Use a lambda do avoid writing the object header when the object is empty ActiveBufferProto* activeBufferProto = getActiveBufferProto(); - activeBufferProto->set_width(buffer.getBuffer()->getWidth()); - activeBufferProto->set_height(buffer.getBuffer()->getHeight()); - activeBufferProto->set_format(buffer.getBuffer()->getPixelFormat()); - activeBufferProto->set_usage(buffer.getBuffer()->getUsage()); + activeBufferProto->set_width(buffer.getWidth()); + activeBufferProto->set_height(buffer.getHeight()); + activeBufferProto->set_stride(buffer.getUsage()); + activeBufferProto->set_format(buffer.getPixelFormat()); } } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 980d1dca54..5991b86d5d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -250,11 +250,6 @@ struct SCOPED_CAPABILITY TimedLock { const status_t status; }; -struct SCOPED_CAPABILITY UnnecessaryLock { - explicit UnnecessaryLock(Mutex& mutex) ACQUIRE(mutex) {} - ~UnnecessaryLock() RELEASE() {} -}; - // TODO(b/141333600): Consolidate with DisplayMode::Builder::getDefaultDensity. constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV; @@ -5102,11 +5097,9 @@ void SurfaceFlinger::dumpWideColorInfo(std::string& result) const { } LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const { - const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); - LayersProto layersProto; for (const sp& layer : mDrawingState.layersSortedByZ) { - layer->writeToProto(layersProto, traceFlags, display.get()); + layer->writeToProto(layersProto, traceFlags); } return layersProto; @@ -5147,8 +5140,7 @@ void SurfaceFlinger::dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t rootProto->add_children(offscreenLayer->sequence); // Add layer - LayerProto* layerProto = - offscreenLayer->writeToProto(layersProto, traceFlags, nullptr /*device*/); + LayerProto* layerProto = offscreenLayer->writeToProto(layersProto, traceFlags); layerProto->set_parent(offscreenRootLayerId); } } @@ -5743,9 +5735,9 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } case 1025: { // Set layer tracing n = data.readInt32(); - int64_t fixedStartingTime = data.readInt64(); bool tracingEnabledChanged; - if (n) { + if (n == 1) { + int64_t fixedStartingTime = data.readInt64(); ALOGD("LayerTracing enabled"); tracingEnabledChanged = mLayerTracing.enable(); if (tracingEnabledChanged) { @@ -5757,6 +5749,10 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r }) .wait(); } + } else if (n == 2) { + std::string filename = std::string(data.readCString()); + ALOGD("LayerTracing disabled. Trace wrote to %s", filename.c_str()); + tracingEnabledChanged = mLayerTracing.disable(filename.c_str()); } else { ALOGD("LayerTracing disabled"); tracingEnabledChanged = mLayerTracing.disable(); @@ -6009,9 +6005,9 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r mTransactionTracing->setBufferSize( TransactionTracing::ACTIVE_TRACING_BUFFER_SIZE); } else { + mTransactionTracing->writeToFile(); mTransactionTracing->setBufferSize( TransactionTracing::CONTINUOUS_TRACING_BUFFER_SIZE); - mTransactionTracing->writeToFile(); } } reply->writeInt32(NO_ERROR); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 95255738c6..02d5f1e49e 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -177,6 +177,11 @@ struct SurfaceFlingerBE { std::atomic mLastSwapTime = 0; }; +struct SCOPED_CAPABILITY UnnecessaryLock { + explicit UnnecessaryLock(Mutex& mutex) ACQUIRE(mutex) {} + ~UnnecessaryLock() RELEASE() {} +}; + class SurfaceFlinger : public BnSurfaceComposer, public PriorityDumper, private IBinder::DeathRecipient, diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp index 006efdfd61..49554c7dd8 100644 --- a/services/surfaceflinger/Tracing/LayerTracing.cpp +++ b/services/surfaceflinger/Tracing/LayerTracing.cpp @@ -45,14 +45,14 @@ bool LayerTracing::enable() { return true; } -bool LayerTracing::disable() { +bool LayerTracing::disable(std::string filename) { std::scoped_lock lock(mTraceLock); if (!mEnabled) { return false; } mEnabled = false; LayersTraceFileProto fileProto = createTraceFileProto(); - mBuffer->writeToFile(fileProto, FILE_NAME); + mBuffer->writeToFile(fileProto, filename); mBuffer->reset(); return true; } diff --git a/services/surfaceflinger/Tracing/LayerTracing.h b/services/surfaceflinger/Tracing/LayerTracing.h index bd448c956d..88a19ecdf1 100644 --- a/services/surfaceflinger/Tracing/LayerTracing.h +++ b/services/surfaceflinger/Tracing/LayerTracing.h @@ -43,7 +43,7 @@ public: LayerTracing(SurfaceFlinger& flinger); ~LayerTracing(); bool enable(); - bool disable(); + bool disable(std::string filename = FILE_NAME); bool isEnabled() const; status_t writeToFile(); LayersTraceFileProto createTraceFileProto() const; diff --git a/services/surfaceflinger/Tracing/RingBuffer.h b/services/surfaceflinger/Tracing/RingBuffer.h index 3b2626d489..7e38c55840 100644 --- a/services/surfaceflinger/Tracing/RingBuffer.h +++ b/services/surfaceflinger/Tracing/RingBuffer.h @@ -67,7 +67,7 @@ public: // -rw-r--r-- const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; if (!android::base::WriteStringToFile(output, filename, mode, getuid(), getgid(), true)) { - ALOGE("Could not save the proto file."); + ALOGE("Could not save the proto file %s", filename.c_str()); return PERMISSION_DENIED; } return NO_ERROR; diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp index 298e63ab67..d5e837f879 100644 --- a/services/surfaceflinger/Tracing/TransactionTracing.cpp +++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp @@ -99,11 +99,11 @@ TransactionTracing::~TransactionTracing() { writeToFile(); } -status_t TransactionTracing::writeToFile() { +status_t TransactionTracing::writeToFile(std::string filename) { std::scoped_lock lock(mTraceLock); proto::TransactionTraceFile fileProto = createTraceFileProto(); addStartingStateToProtoLocked(fileProto); - return mBuffer.writeToFile(fileProto, FILE_NAME); + return mBuffer.writeToFile(fileProto, filename); } void TransactionTracing::setBufferSize(size_t bufferSizeInBytes) { diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h index c20f22a94b..95256c4047 100644 --- a/services/surfaceflinger/Tracing/TransactionTracing.h +++ b/services/surfaceflinger/Tracing/TransactionTracing.h @@ -55,7 +55,7 @@ public: void addQueuedTransaction(const TransactionState&); void addCommittedTransactions(std::vector& transactions, int64_t vsyncId); - status_t writeToFile(); + status_t writeToFile(std::string filename = FILE_NAME); void setBufferSize(size_t bufferSizeInBytes); void onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name, uint32_t flags, int parentId); -- cgit v1.2.3-59-g8ed1b From d6a36206879babb56ad58f4b14d4f72e80329c82 Mon Sep 17 00:00:00 2001 From: Andy Yu Date: Wed, 26 Jan 2022 04:08:22 -0800 Subject: Add FrameRateOverrideMappings unit test - Add unit test - Modify Scheduler and FrameRateOverrideMappings to check supportFrameRateOverrideByContent in getAllFrameRateOverrides - Remove flag usage in Scheduler to keep it within FrameRateOverrideMappings class - Add operator== for FrameRateOverride event to enable ASSERT_EQ Bug: b/204322816, b/216445833 Test: atest libsurfaceflinger_unittest:FrameRateOverrideMappingsTest Change-Id: Ie8717e76cb1bcfeefac93a7093ee30581767c18b --- libs/gui/include/gui/DisplayEventReceiver.h | 5 + .../Scheduler/FrameRateOverrideMappings.cpp | 8 +- .../Scheduler/FrameRateOverrideMappings.h | 3 +- services/surfaceflinger/Scheduler/Scheduler.cpp | 12 +- services/surfaceflinger/tests/unittests/Android.bp | 1 + .../unittests/FrameRateOverrideMappingsTest.cpp | 185 +++++++++++++++++++++ 6 files changed, 208 insertions(+), 6 deletions(-) create mode 100644 services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index db41c32549..29d5c0c33b 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -177,6 +177,11 @@ private: std::unique_ptr mDataChannel; }; +inline bool operator==(DisplayEventReceiver::Event::FrameRateOverride lhs, + DisplayEventReceiver::Event::FrameRateOverride rhs) { + return (lhs.uid == rhs.uid) && std::abs(lhs.frameRateHz - rhs.frameRateHz) < 0.001f; +} + // ---------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp index d9d64ae9db..c233455994 100644 --- a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp +++ b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp @@ -51,7 +51,8 @@ std::optional FrameRateOverrideMappings::getFrameRateOverrideForUid( return std::nullopt; } -std::vector FrameRateOverrideMappings::getAllFrameRateOverrides() { +std::vector FrameRateOverrideMappings::getAllFrameRateOverrides( + bool supportsFrameRateOverrideByContent) { std::lock_guard lock(mFrameRateOverridesLock); std::vector overrides; overrides.reserve(std::max({mFrameRateOverridesFromGameManager.size(), @@ -67,6 +68,11 @@ std::vector FrameRateOverrideMappings::getAllFrameRateOverrid overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()}); } } + + if (!supportsFrameRateOverrideByContent) { + return overrides; + } + for (const auto& [uid, frameRate] : mFrameRateOverridesByContent) { if (std::find_if(overrides.begin(), overrides.end(), [uid = uid](auto i) { return i.uid == uid; }) == overrides.end()) { diff --git a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h index 278f87c30f..4185a4c0ab 100644 --- a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h +++ b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h @@ -32,7 +32,8 @@ public: std::optional getFrameRateOverrideForUid(uid_t uid, bool supportsFrameRateOverrideByContent) const EXCLUDES(mFrameRateOverridesLock); - std::vector getAllFrameRateOverrides() EXCLUDES(mFrameRateOverridesLock); + std::vector getAllFrameRateOverrides(bool supportsFrameRateOverrideByContent) + EXCLUDES(mFrameRateOverridesLock); void dump(std::string& result) const; bool updateFrameRateOverridesByContent(const UidToFrameRateOverride& frameRateOverrides) EXCLUDES(mFrameRateOverridesLock); diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 665d36982a..a80ba6641c 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -262,8 +262,12 @@ void Scheduler::onScreenReleased(ConnectionHandle handle) { } void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId) { + const auto refreshRateConfigs = holdRefreshRateConfigs(); + const bool supportsFrameRateOverrideByContent = + refreshRateConfigs->supportsFrameRateOverrideByContent(); + std::vector overrides = - mFrameRateOverrideMappings.getAllFrameRateOverrides(); + mFrameRateOverrideMappings.getAllFrameRateOverrides(supportsFrameRateOverrideByContent); android::EventThread* thread; { @@ -681,10 +685,10 @@ void Scheduler::dumpVsync(std::string& out) const { bool Scheduler::updateFrameRateOverrides(GlobalSignals consideredSignals, Fps displayRefreshRate) { const auto refreshRateConfigs = holdRefreshRateConfigs(); - if (!refreshRateConfigs->supportsFrameRateOverrideByContent()) { - return false; - } + // we always update mFrameRateOverridesByContent here + // supportsFrameRateOverridesByContent will be checked + // when getting FrameRateOverrides from mFrameRateOverrideMappings if (!consideredSignals.idle) { const auto frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(mPolicy.contentRequirements, diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 48f18b9bed..1db5e613f8 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -80,6 +80,7 @@ cc_test { "FpsReporterTest.cpp", "FpsTest.cpp", "FramebufferSurfaceTest.cpp", + "FrameRateOverrideMappingsTest.cpp", "FrameTimelineTest.cpp", "GameModeTest.cpp", "HWComposerTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp b/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp new file mode 100644 index 0000000000..a581c7a4a4 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp @@ -0,0 +1,185 @@ +/* + * 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. + */ + +#undef LOG_TAG +#define LOG_TAG "FrameRateOverrideMappingsTest" + +#include +#include + +#include "Scheduler/FrameRateOverrideMappings.h" + +namespace android::scheduler { + +using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; +using UidToFrameRateOverride = std::map; + +class FrameRateOverrideMappingsTest : public testing::Test { +protected: + FrameRateOverrideMappings mFrameRateOverrideMappings; + UidToFrameRateOverride mFrameRateOverrideByContent; +}; + +namespace { +TEST_F(FrameRateOverrideMappingsTest, testUpdateFrameRateOverridesByContent) { + mFrameRateOverrideByContent.clear(); + mFrameRateOverrideByContent.emplace(0, 30.0_Hz); + mFrameRateOverrideByContent.emplace(1, 60.0_Hz); + ASSERT_TRUE(mFrameRateOverrideMappings.updateFrameRateOverridesByContent( + mFrameRateOverrideByContent)); + + ASSERT_TRUE(isApproxEqual(30.0_Hz, + *mFrameRateOverrideMappings.getFrameRateOverrideForUid( + 0, /*supportsFrameRateOverrideByContent*/ true))); + ASSERT_TRUE(isApproxEqual(60.0_Hz, + *mFrameRateOverrideMappings.getFrameRateOverrideForUid( + 1, /*supportsFrameRateOverrideByContent*/ true))); + ASSERT_EQ(std::nullopt, + mFrameRateOverrideMappings + .getFrameRateOverrideForUid(1, /*supportsFrameRateOverrideByContent*/ false)); + ASSERT_EQ(std::nullopt, + mFrameRateOverrideMappings + .getFrameRateOverrideForUid(3, /*supportsFrameRateOverrideByContent*/ true)); + ASSERT_EQ(std::nullopt, + mFrameRateOverrideMappings + .getFrameRateOverrideForUid(3, /*supportsFrameRateOverrideByContent*/ false)); +} + +TEST_F(FrameRateOverrideMappingsTest, testSetGameModeRefreshRateForUid) { + mFrameRateOverrideMappings.setGameModeRefreshRateForUid({1, 30.0f}); + mFrameRateOverrideMappings.setGameModeRefreshRateForUid({2, 90.0f}); + + ASSERT_TRUE(isApproxEqual(30.0_Hz, + *mFrameRateOverrideMappings.getFrameRateOverrideForUid( + 1, /*supportsFrameRateOverrideByContent*/ true))); + ASSERT_TRUE(isApproxEqual(90.0_Hz, + *mFrameRateOverrideMappings.getFrameRateOverrideForUid( + 2, /*supportsFrameRateOverrideByContent*/ false))); + ASSERT_EQ(std::nullopt, + mFrameRateOverrideMappings + .getFrameRateOverrideForUid(0, /*supportsFrameRateOverrideByContent*/ true)); + ASSERT_EQ(std::nullopt, + mFrameRateOverrideMappings + .getFrameRateOverrideForUid(0, /*supportsFrameRateOverrideByContent*/ false)); +} + +TEST_F(FrameRateOverrideMappingsTest, testSetPreferredRefreshRateForUid) { + mFrameRateOverrideMappings.setPreferredRefreshRateForUid({0, 60.0f}); + mFrameRateOverrideMappings.setPreferredRefreshRateForUid({2, 120.0f}); + + ASSERT_TRUE(isApproxEqual(60.0_Hz, + *mFrameRateOverrideMappings.getFrameRateOverrideForUid( + 0, /*supportsFrameRateOverrideByContent*/ true))); + ASSERT_TRUE(isApproxEqual(120.0_Hz, + *mFrameRateOverrideMappings.getFrameRateOverrideForUid( + 2, /*supportsFrameRateOverrideByContent*/ false))); + ASSERT_EQ(std::nullopt, + mFrameRateOverrideMappings + .getFrameRateOverrideForUid(1, /*supportsFrameRateOverrideByContent*/ true)); + ASSERT_EQ(std::nullopt, + mFrameRateOverrideMappings + .getFrameRateOverrideForUid(1, /*supportsFrameRateOverrideByContent*/ false)); +} + +TEST_F(FrameRateOverrideMappingsTest, testGetFrameRateOverrideForUidMixed) { + mFrameRateOverrideByContent.clear(); + mFrameRateOverrideByContent.emplace(0, 30.0_Hz); + mFrameRateOverrideByContent.emplace(1, 60.0_Hz); + mFrameRateOverrideByContent.emplace(2, 45.0_Hz); + mFrameRateOverrideByContent.emplace(5, 120.0_Hz); + ASSERT_TRUE(mFrameRateOverrideMappings.updateFrameRateOverridesByContent( + mFrameRateOverrideByContent)); + + std::vector allFrameRateOverrides; + ASSERT_EQ(allFrameRateOverrides, + mFrameRateOverrideMappings.getAllFrameRateOverrides( + /*supportsFrameRateOverrideByContent*/ false)); + allFrameRateOverrides = {{0, 30.0f}, {1, 60.0f}, {2, 45.0f}, {5, 120.0f}}; + ASSERT_EQ(allFrameRateOverrides, + mFrameRateOverrideMappings.getAllFrameRateOverrides( + /*supportsFrameRateOverrideByContent*/ true)); + + mFrameRateOverrideMappings.setGameModeRefreshRateForUid({1, 30.0f}); + mFrameRateOverrideMappings.setGameModeRefreshRateForUid({2, 90.0f}); + mFrameRateOverrideMappings.setGameModeRefreshRateForUid({4, 120.0f}); + + allFrameRateOverrides.clear(); + allFrameRateOverrides = {{1, 30.0f}, {2, 90.0f}, {4, 120.0f}}; + ASSERT_EQ(allFrameRateOverrides, + mFrameRateOverrideMappings.getAllFrameRateOverrides( + /*supportsFrameRateOverrideByContent*/ false)); + allFrameRateOverrides.clear(); + allFrameRateOverrides = {{1, 30.0f}, {2, 90.0f}, {4, 120.0f}, {0, 30.0f}, {5, 120.0f}}; + ASSERT_EQ(allFrameRateOverrides, + mFrameRateOverrideMappings.getAllFrameRateOverrides( + /*supportsFrameRateOverrideByContent*/ true)); + + mFrameRateOverrideMappings.setPreferredRefreshRateForUid({0, 60.0f}); + mFrameRateOverrideMappings.setPreferredRefreshRateForUid({2, 120.0f}); + mFrameRateOverrideMappings.setPreferredRefreshRateForUid({3, 30.0f}); + + allFrameRateOverrides.clear(); + allFrameRateOverrides = {{0, 60.0f}, {2, 120.0f}, {3, 30.0f}, {1, 30.0f}, {4, 120.0f}}; + ASSERT_EQ(allFrameRateOverrides, + mFrameRateOverrideMappings.getAllFrameRateOverrides( + /*supportsFrameRateOverrideByContent*/ false)); + allFrameRateOverrides.clear(); + allFrameRateOverrides = {{0, 60.0f}, {2, 120.0f}, {3, 30.0f}, + {1, 30.0f}, {4, 120.0f}, {5, 120.0f}}; + ASSERT_EQ(allFrameRateOverrides, + mFrameRateOverrideMappings.getAllFrameRateOverrides( + /*supportsFrameRateOverrideByContent*/ true)); + + ASSERT_TRUE(isApproxEqual(60.0_Hz, + *mFrameRateOverrideMappings.getFrameRateOverrideForUid( + 0, /*supportsFrameRateOverrideByContent*/ true))); + ASSERT_TRUE(isApproxEqual(30.0_Hz, + *mFrameRateOverrideMappings.getFrameRateOverrideForUid( + 1, /*supportsFrameRateOverrideByContent*/ true))); + ASSERT_TRUE(isApproxEqual(120.0_Hz, + *mFrameRateOverrideMappings.getFrameRateOverrideForUid( + 2, /*supportsFrameRateOverrideByContent*/ true))); + ASSERT_TRUE(isApproxEqual(30.0_Hz, + *mFrameRateOverrideMappings.getFrameRateOverrideForUid( + 3, /*supportsFrameRateOverrideByContent*/ true))); + ASSERT_TRUE(isApproxEqual(120.0_Hz, + *mFrameRateOverrideMappings.getFrameRateOverrideForUid( + 4, /*supportsFrameRateOverrideByContent*/ true))); + ASSERT_TRUE(isApproxEqual(120.0_Hz, + *mFrameRateOverrideMappings.getFrameRateOverrideForUid( + 5, /*supportsFrameRateOverrideByContent*/ true))); + + ASSERT_TRUE(isApproxEqual(60.0_Hz, + *mFrameRateOverrideMappings.getFrameRateOverrideForUid( + 0, /*supportsFrameRateOverrideByContent*/ false))); + ASSERT_TRUE(isApproxEqual(30.0_Hz, + *mFrameRateOverrideMappings.getFrameRateOverrideForUid( + 1, /*supportsFrameRateOverrideByContent*/ false))); + ASSERT_TRUE(isApproxEqual(120.0_Hz, + *mFrameRateOverrideMappings.getFrameRateOverrideForUid( + 2, /*supportsFrameRateOverrideByContent*/ false))); + ASSERT_TRUE(isApproxEqual(30.0_Hz, + *mFrameRateOverrideMappings.getFrameRateOverrideForUid( + 3, /*supportsFrameRateOverrideByContent*/ false))); + ASSERT_TRUE(isApproxEqual(120.0_Hz, + *mFrameRateOverrideMappings.getFrameRateOverrideForUid( + 4, /*supportsFrameRateOverrideByContent*/ false))); + ASSERT_EQ(std::nullopt, + mFrameRateOverrideMappings + .getFrameRateOverrideForUid(5, /*supportsFrameRateOverrideByContent*/ false)); +} +} // namespace +} // namespace android::scheduler -- cgit v1.2.3-59-g8ed1b From 240bb02edf757a51fb1480f1c812064ea6865a1a Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Fri, 11 Feb 2022 16:18:11 -0800 Subject: Add AHARDWAREBUFFER_FORMAT_YCBCR_P010 ... which corresponds to HAL_PIXEL_FORMAT_YCBCR_P010. (aosp/1982996) Bug: b/207388558 Test: build and boot Cuttlefish with P010 SwiftShader support Change-Id: Ia07db989845da4dfe1d26fa1541abd9d768ad92a --- libs/nativewindow/AHardwareBuffer.cpp | 4 ++++ libs/nativewindow/include/android/hardware_buffer.h | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index 2578ee8467..381900e4ba 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -584,6 +584,8 @@ bool AHardwareBuffer_isValidPixelFormat(uint32_t format) { "HAL and AHardwareBuffer pixel format don't match"); static_assert(HAL_PIXEL_FORMAT_YCBCR_422_I == AHARDWAREBUFFER_FORMAT_YCbCr_422_I, "HAL and AHardwareBuffer pixel format don't match"); + static_assert(HAL_PIXEL_FORMAT_YCBCR_P010 == AHARDWAREBUFFER_FORMAT_YCbCr_P010, + "HAL and AHardwareBuffer pixel format don't match"); static_assert(static_cast(aidl::android::hardware::graphics::common::PixelFormat::R_8) == AHARDWAREBUFFER_FORMAT_R8_UNORM, "HAL and AHardwareBuffer pixel format don't match"); @@ -617,6 +619,7 @@ bool AHardwareBuffer_isValidPixelFormat(uint32_t format) { case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP: case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP: case AHARDWAREBUFFER_FORMAT_YCbCr_422_I: + case AHARDWAREBUFFER_FORMAT_YCbCr_P010: return true; default: @@ -633,6 +636,7 @@ bool AHardwareBuffer_formatIsYuv(uint32_t format) { case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP: case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP: case AHARDWAREBUFFER_FORMAT_YCbCr_422_I: + case AHARDWAREBUFFER_FORMAT_YCbCr_P010: return true; default: return false; diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h index 6f1f04df34..c35507b6f1 100644 --- a/libs/nativewindow/include/android/hardware_buffer.h +++ b/libs/nativewindow/include/android/hardware_buffer.h @@ -159,6 +159,14 @@ enum AHardwareBuffer_Format { */ AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420 = 0x23, + /** + * YUV P010 format. + * Must have an even width and height. Can be accessed in OpenGL + * shaders through an external sampler. Does not support mip-maps + * cube-maps or multi-layered textures. + */ + AHARDWAREBUFFER_FORMAT_YCbCr_P010 = 0x36, + /** * Corresponding formats: * Vulkan: VK_FORMAT_R8_UNORM -- cgit v1.2.3-59-g8ed1b From 0c41ffa1bd99abbd5ea5d39db506083bfe821ef9 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Fri, 24 Dec 2021 16:45:12 -0800 Subject: SF: Dedupe functions to apply Scheduler::Policy The only functional difference is the early out when there is no change in timer state, which now applies to LayerRequirement state as well. Bug: 185535769 Test: libsurfaceflinger_unittest Change-Id: Ia7234847e4f44d78dbf3920d77f38f3bfa40e5a2 --- services/surfaceflinger/Scheduler/LayerHistory.cpp | 46 +++++---------- services/surfaceflinger/Scheduler/LayerHistory.h | 10 ++-- services/surfaceflinger/Scheduler/Scheduler.cpp | 69 ++++++---------------- services/surfaceflinger/Scheduler/Scheduler.h | 13 ++-- .../tests/unittests/LayerHistoryTest.cpp | 2 +- .../tests/unittests/SchedulerTest.cpp | 7 ++- 6 files changed, 53 insertions(+), 94 deletions(-) diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 0efc28b71d..5f64efa3d1 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -83,8 +83,7 @@ LayerHistory::~LayerHistory() = default; void LayerHistory::registerLayer(Layer* layer, LayerVoteType type) { std::lock_guard lock(mLock); - LOG_ALWAYS_FATAL_IF(findLayer(layer->getSequence()).first != - LayerHistory::layerStatus::NotFound, + LOG_ALWAYS_FATAL_IF(findLayer(layer->getSequence()).first != LayerStatus::NotFound, "%s already registered", layer->getName().c_str()); auto info = std::make_unique(layer->getName(), layer->getOwnerUid(), type); @@ -108,9 +107,9 @@ void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now, auto id = layer->getSequence(); auto [found, layerPair] = findLayer(id); - if (found == LayerHistory::layerStatus::NotFound) { + if (found == LayerStatus::NotFound) { // Offscreen layer - ALOGV("LayerHistory::record: %s not registered", layer->getName().c_str()); + ALOGV("%s: %s not registered", __func__, layer->getName().c_str()); return; } @@ -126,16 +125,15 @@ void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now, info->setLastPresentTime(presentTime, now, updateType, mModeChangePending, layerProps); // Activate layer if inactive. - if (found == LayerHistory::layerStatus::LayerInInactiveMap) { + if (found == LayerStatus::LayerInInactiveMap) { mActiveLayerInfos.insert( {id, std::make_pair(layerPair->first, std::move(layerPair->second))}); mInactiveLayerInfos.erase(id); } } -LayerHistory::Summary LayerHistory::summarize(const RefreshRateConfigs& refreshRateConfigs, - nsecs_t now) { - LayerHistory::Summary summary; +auto LayerHistory::summarize(const RefreshRateConfigs& configs, nsecs_t now) -> Summary { + Summary summary; std::lock_guard lock(mLock); @@ -148,9 +146,9 @@ LayerHistory::Summary LayerHistory::summarize(const RefreshRateConfigs& refreshR ALOGV("%s has priority: %d %s focused", info->getName().c_str(), frameRateSelectionPriority, layerFocused ? "" : "not"); - const auto vote = info->getRefreshRateVote(refreshRateConfigs, now); + const auto vote = info->getRefreshRateVote(configs, now); // Skip NoVote layer as those don't have any requirements - if (vote.type == LayerHistory::LayerVoteType::NoVote) { + if (vote.type == LayerVoteType::NoVote) { continue; } @@ -187,7 +185,7 @@ void LayerHistory::partitionLayers(nsecs_t now) { it = mInactiveLayerInfos.erase(it); } else { if (CC_UNLIKELY(mTraceEnabled)) { - trace(*info, LayerHistory::LayerVoteType::NoVote, 0); + trace(*info, LayerVoteType::NoVote, 0); } info->onLayerInactive(now); it++; @@ -224,7 +222,7 @@ void LayerHistory::partitionLayers(nsecs_t now) { it++; } else { if (CC_UNLIKELY(mTraceEnabled)) { - trace(*info, LayerHistory::LayerVoteType::NoVote, 0); + trace(*info, LayerVoteType::NoVote, 0); } info->onLayerInactive(now); // move this to the inactive map @@ -251,37 +249,23 @@ std::string LayerHistory::dump() const { float LayerHistory::getLayerFramerate(nsecs_t now, int32_t id) const { std::lock_guard lock(mLock); auto [found, layerPair] = findLayer(id); - if (found != LayerHistory::layerStatus::NotFound) { + if (found != LayerStatus::NotFound) { return layerPair->second->getFps(now).getValue(); } return 0.f; } -std::pair LayerHistory::findLayer(int32_t id) { +auto LayerHistory::findLayer(int32_t id) -> std::pair { // the layer could be in either the active or inactive map, try both auto it = mActiveLayerInfos.find(id); if (it != mActiveLayerInfos.end()) { - return std::make_pair(LayerHistory::layerStatus::LayerInActiveMap, &(it->second)); + return {LayerStatus::LayerInActiveMap, &(it->second)}; } it = mInactiveLayerInfos.find(id); if (it != mInactiveLayerInfos.end()) { - return std::make_pair(LayerHistory::layerStatus::LayerInInactiveMap, &(it->second)); + return {LayerStatus::LayerInInactiveMap, &(it->second)}; } - return std::make_pair(LayerHistory::layerStatus::NotFound, nullptr); -} - -std::pair LayerHistory::findLayer( - int32_t id) const { - // the layer could be in either the active or inactive map, try both - auto it = mActiveLayerInfos.find(id); - if (it != mActiveLayerInfos.end()) { - return std::make_pair(LayerHistory::layerStatus::LayerInActiveMap, &(it->second)); - } - it = mInactiveLayerInfos.find(id); - if (it != mInactiveLayerInfos.end()) { - return std::make_pair(LayerHistory::layerStatus::LayerInInactiveMap, &(it->second)); - } - return std::make_pair(LayerHistory::layerStatus::NotFound, nullptr); + return {LayerStatus::NotFound, nullptr}; } } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index cc55700503..7b6096f7f3 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -89,7 +89,7 @@ private: // worst case time complexity is O(2 * inactive + active) void partitionLayers(nsecs_t now) REQUIRES(mLock); - enum class layerStatus { + enum class LayerStatus { NotFound, LayerInActiveMap, LayerInInactiveMap, @@ -97,9 +97,11 @@ private: // looks up a layer by sequence id in both layerInfo maps. // The first element indicates if and where the item was found - std::pair findLayer(int32_t id) REQUIRES(mLock); - std::pair findLayer(int32_t id) const - REQUIRES(mLock); + std::pair findLayer(int32_t id) REQUIRES(mLock); + + std::pair findLayer(int32_t id) const REQUIRES(mLock) { + return const_cast(this)->findLayer(id); + } mutable std::mutex mLock; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index de27bd1823..2690716961 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -531,50 +531,13 @@ void Scheduler::setModeChangePending(bool pending) { } void Scheduler::chooseRefreshRateForContent() { - { - std::scoped_lock lock(mRefreshRateConfigsLock); - if (!mRefreshRateConfigs->canSwitch()) return; - } + const auto configs = holdRefreshRateConfigs(); + if (!configs->canSwitch()) return; ATRACE_CALL(); - DisplayModePtr newMode; - GlobalSignals consideredSignals; - - bool frameRateChanged; - bool frameRateOverridesChanged; - - const auto refreshRateConfigs = holdRefreshRateConfigs(); - LayerHistory::Summary summary = mLayerHistory.summarize(*refreshRateConfigs, systemTime()); - { - std::lock_guard lock(mPolicyLock); - mPolicy.contentRequirements = std::move(summary); - - std::tie(newMode, consideredSignals) = chooseDisplayMode(); - frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); - - if (mPolicy.mode == newMode) { - // We don't need to change the display mode, but we might need to send an event - // about a mode change, since it was suppressed due to a previous idleConsidered - if (!consideredSignals.idle) { - dispatchCachedReportedMode(); - } - frameRateChanged = false; - } else { - mPolicy.mode = newMode; - frameRateChanged = true; - } - } - if (frameRateChanged) { - const auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); - - mSchedulerCallback.changeRefreshRate(newRefreshRate, - consideredSignals.idle ? DisplayModeEvent::None - : DisplayModeEvent::Changed); - } - if (frameRateOverridesChanged) { - mSchedulerCallback.triggerOnFrameRateOverridesChanged(); - } + LayerHistory::Summary summary = mLayerHistory.summarize(*configs, systemTime()); + applyPolicy(&Policy::contentRequirements, std::move(summary)); } void Scheduler::resetIdleTimer() { @@ -636,7 +599,7 @@ void Scheduler::kernelIdleTimerCallback(TimerState state) { } void Scheduler::idleTimerCallback(TimerState state) { - handleTimerStateChanged(&mPolicy.idleTimer, state); + applyPolicy(&Policy::idleTimer, state); ATRACE_INT("ExpiredIdleTimer", static_cast(state)); } @@ -646,14 +609,14 @@ void Scheduler::touchTimerCallback(TimerState state) { // Clear layer history to get fresh FPS detection. // NOTE: Instead of checking all the layers, we should be checking the layer // that is currently on top. b/142507166 will give us this capability. - if (handleTimerStateChanged(&mPolicy.touch, touch)) { + if (applyPolicy(&Policy::touch, touch).touch) { mLayerHistory.clear(); } ATRACE_INT("TouchState", static_cast(touch)); } void Scheduler::displayPowerTimerCallback(TimerState state) { - handleTimerStateChanged(&mPolicy.displayPowerTimer, state); + applyPolicy(&Policy::displayPowerTimer, state); ATRACE_INT("ExpiredDisplayPowerTimer", static_cast(state)); } @@ -695,8 +658,8 @@ bool Scheduler::updateFrameRateOverrides(GlobalSignals consideredSignals, Fps di return false; } -template -bool Scheduler::handleTimerStateChanged(T* currentState, T newState) { +template +auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals { DisplayModePtr newMode; GlobalSignals consideredSignals; @@ -706,15 +669,17 @@ bool Scheduler::handleTimerStateChanged(T* currentState, T newState) { const auto refreshRateConfigs = holdRefreshRateConfigs(); { std::lock_guard lock(mPolicyLock); - if (*currentState == newState) { - return false; - } - *currentState = newState; + + auto& currentState = mPolicy.*statePtr; + if (currentState == newState) return {}; + currentState = std::forward(newState); + std::tie(newMode, consideredSignals) = chooseDisplayMode(); frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); + if (mPolicy.mode == newMode) { // We don't need to change the display mode, but we might need to send an event - // about a mode change, since it was suppressed due to a previous idleConsidered + // about a mode change, since it was suppressed if previously considered idle. if (!consideredSignals.idle) { dispatchCachedReportedMode(); } @@ -733,7 +698,7 @@ bool Scheduler::handleTimerStateChanged(T* currentState, T newState) { if (frameRateOverridesChanged) { mSchedulerCallback.triggerOnFrameRateOverridesChanged(); } - return consideredSignals.touch; + return consideredSignals; } auto Scheduler::chooseDisplayMode() -> std::pair { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 468c4cc865..9c32b1f421 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -263,14 +263,17 @@ private: void touchTimerCallback(TimerState); void displayPowerTimerCallback(TimerState); - // handles various timer features to change the refresh rate. - template - bool handleTimerStateChanged(T* currentState, T newState); - void setVsyncPeriod(nsecs_t period); using GlobalSignals = RefreshRateConfigs::GlobalSignals; + struct Policy; + + // Sets the S state of the policy to the T value under mPolicyLock, and chooses a display mode + // that fulfills the new policy if the state changed. Returns the signals that were considered. + template + GlobalSignals applyPolicy(S Policy::*, T&&) EXCLUDES(mPolicyLock); + // Returns the display mode that fulfills the policy, and the signals that were considered. std::pair chooseDisplayMode() REQUIRES(mPolicyLock); @@ -323,7 +326,7 @@ private: mutable std::mutex mPolicyLock; - struct { + struct Policy { // Policy for choosing the display mode. LayerHistory::Summary contentRequirements; TimerState idleTimer = TimerState::Reset; diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index cdb2240b40..e108beaca9 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -97,7 +97,7 @@ protected: void setDefaultLayerVote(Layer* layer, LayerHistory::LayerVoteType vote) NO_THREAD_SAFETY_ANALYSIS { auto [found, layerPair] = history().findLayer(layer->getSequence()); - if (found != LayerHistory::layerStatus::NotFound) { + if (found != LayerHistory::LayerStatus::NotFound) { layerPair->second->setDefaultLayerVote(vote); } } diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index f48abb7519..a992a91226 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -228,7 +228,8 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { mScheduler->setRefreshRateConfigs( std::make_shared(DisplayModes{mode60, mode120}, mode60->getId())); - sp layer = sp::make(mFlinger.flinger()); + const sp layer = sp::make(mFlinger.flinger()); + EXPECT_CALL(*layer, isVisible()).WillOnce(Return(true)); mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer); @@ -240,6 +241,10 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { EXPECT_CALL(mSchedulerCallback, changeRefreshRate(Is120Hz(), _)).Times(1); mScheduler->chooseRefreshRateForContent(); + + // No-op if layer requirements have not changed. + EXPECT_CALL(mSchedulerCallback, changeRefreshRate(_, _)).Times(0); + mScheduler->chooseRefreshRateForContent(); } } // namespace android::scheduler -- cgit v1.2.3-59-g8ed1b From 4c1978562d7b476952cb9c468be3e09ea64b1ccd Mon Sep 17 00:00:00 2001 From: Evan Severson Date: Thu, 27 Jan 2022 10:44:27 -0800 Subject: Upadate sensor service to use new sensor privacy api The new calls no longer require user ids since that is managed internally in the sensor privacy service and calling services will receive updates when the state is changed or user is changed who has a different setting. Calling services should treat the state as a global setting. The new calls also support hardware and software types of controls. This change treats both the same. Test: atest CtsSensorRatePermissionTestCases Bug: 191745272 Change-Id: Ifa905110b0b75fbc48a37b7e49e269621f03129d --- services/sensorservice/SensorService.cpp | 108 ++++++++++++++----------------- services/sensorservice/SensorService.h | 35 ++++++---- 2 files changed, 68 insertions(+), 75 deletions(-) diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index 971491dbef..3c164aadd9 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -134,6 +134,7 @@ SensorService::SensorService() mWakeLockAcquired(false), mLastReportedProxIsActive(false) { mUidPolicy = new UidPolicy(this); mSensorPrivacyPolicy = new SensorPrivacyPolicy(this); + mMicSensorPrivacyPolicy = new MicrophonePrivacyPolicy(this); } bool SensorService::initializeHmacKey() { @@ -369,6 +370,9 @@ void SensorService::onFirstRef() { // Start watching sensor privacy changes mSensorPrivacyPolicy->registerSelf(); + + // Start watching mic sensor privacy changes + mMicSensorPrivacyPolicy->registerSelf(); } } } @@ -439,9 +443,7 @@ SensorService::~SensorService() { } mUidPolicy->unregisterSelf(); mSensorPrivacyPolicy->unregisterSelf(); - for (auto const& [userId, policy] : mMicSensorPrivacyPolicies) { - policy->unregisterSelf(); - } + mMicSensorPrivacyPolicy->unregisterSelf(); } status_t SensorService::dump(int fd, const Vector& args) { @@ -773,33 +775,25 @@ void SensorService::enableAllSensorsLocked(ConnectionSafeAutolock* connLock) { checkAndReportProxStateChangeLocked(); } -void SensorService::capRates(userid_t userId) { +void SensorService::capRates() { ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock); for (const sp& conn : connLock.getDirectConnections()) { - if (conn->getUserId() == userId) { - conn->onMicSensorAccessChanged(true); - } + conn->onMicSensorAccessChanged(true); } for (const sp& conn : connLock.getActiveConnections()) { - if (conn->getUserId() == userId) { - conn->onMicSensorAccessChanged(true); - } + conn->onMicSensorAccessChanged(true); } } -void SensorService::uncapRates(userid_t userId) { +void SensorService::uncapRates() { ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock); for (const sp& conn : connLock.getDirectConnections()) { - if (conn->getUserId() == userId) { - conn->onMicSensorAccessChanged(false); - } + conn->onMicSensorAccessChanged(false); } for (const sp& conn : connLock.getActiveConnections()) { - if (conn->getUserId() == userId) { - conn->onMicSensorAccessChanged(false); - } + conn->onMicSensorAccessChanged(false); } } @@ -2243,7 +2237,6 @@ bool SensorService::isSensorInCappedSet(int sensorType) { status_t SensorService::adjustSamplingPeriodBasedOnMicAndPermission(nsecs_t* requestedPeriodNs, const String16& opPackageName) { - uid_t uid = IPCThreadState::self()->getCallingUid(); if (*requestedPeriodNs >= SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) { return OK; } @@ -2255,7 +2248,7 @@ status_t SensorService::adjustSamplingPeriodBasedOnMicAndPermission(nsecs_t* req } return OK; } - if (isMicSensorPrivacyEnabledForUid(uid)) { + if (mMicSensorPrivacyPolicy->isSensorPrivacyEnabled()) { *requestedPeriodNs = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS; return OK; } @@ -2264,7 +2257,6 @@ status_t SensorService::adjustSamplingPeriodBasedOnMicAndPermission(nsecs_t* req status_t SensorService::adjustRateLevelBasedOnMicAndPermission(int* requestedRateLevel, const String16& opPackageName) { - uid_t uid = IPCThreadState::self()->getCallingUid(); if (*requestedRateLevel <= SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL) { return OK; } @@ -2276,7 +2268,7 @@ status_t SensorService::adjustRateLevelBasedOnMicAndPermission(int* requestedRat } return OK; } - if (isMicSensorPrivacyEnabledForUid(uid)) { + if (mMicSensorPrivacyPolicy->isSensorPrivacyEnabled()) { *requestedRateLevel = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL; return OK; } @@ -2293,69 +2285,63 @@ void SensorService::SensorPrivacyPolicy::registerSelf() { void SensorService::SensorPrivacyPolicy::unregisterSelf() { AutoCallerClear acc; SensorPrivacyManager spm; - if (mIsIndividualMic) { - spm.removeIndividualSensorPrivacyListener( - SensorPrivacyManager::INDIVIDUAL_SENSOR_MICROPHONE, this); - } else { - spm.removeSensorPrivacyListener(this); - } + spm.removeSensorPrivacyListener(this); } bool SensorService::SensorPrivacyPolicy::isSensorPrivacyEnabled() { return mSensorPrivacyEnabled; } -binder::Status SensorService::SensorPrivacyPolicy::onSensorPrivacyChanged(bool enabled) { +binder::Status SensorService::SensorPrivacyPolicy::onSensorPrivacyChanged(int toggleType __unused, + int sensor __unused, bool enabled) { mSensorPrivacyEnabled = enabled; sp service = mService.promote(); if (service != nullptr) { - if (mIsIndividualMic) { - if (enabled) { - service->capRates(mUserId); - } else { - service->uncapRates(mUserId); - } + if (enabled) { + service->disableAllSensors(); } else { - if (enabled) { - service->disableAllSensors(); - } else { - service->enableAllSensors(); - } + service->enableAllSensors(); } } return binder::Status::ok(); } -status_t SensorService::SensorPrivacyPolicy::registerSelfForIndividual(int userId) { - Mutex::Autolock _l(mSensorPrivacyLock); +void SensorService::MicrophonePrivacyPolicy::registerSelf() { AutoCallerClear acc; SensorPrivacyManager spm; - status_t err = spm.addIndividualSensorPrivacyListener(userId, - SensorPrivacyManager::INDIVIDUAL_SENSOR_MICROPHONE, this); - - if (err != OK) { - ALOGE("Cannot register a mic listener."); - return err; - } - mSensorPrivacyEnabled = spm.isIndividualSensorPrivacyEnabled(userId, - SensorPrivacyManager::INDIVIDUAL_SENSOR_MICROPHONE); + mSensorPrivacyEnabled = + spm.isToggleSensorPrivacyEnabled( + SensorPrivacyManager::TOGGLE_TYPE_SOFTWARE, + SensorPrivacyManager::TOGGLE_SENSOR_MICROPHONE) + || spm.isToggleSensorPrivacyEnabled( + SensorPrivacyManager::TOGGLE_TYPE_HARDWARE, + SensorPrivacyManager::TOGGLE_SENSOR_MICROPHONE); + spm.addToggleSensorPrivacyListener(this); +} - mIsIndividualMic = true; - mUserId = userId; - return OK; +void SensorService::MicrophonePrivacyPolicy::unregisterSelf() { + AutoCallerClear acc; + SensorPrivacyManager spm; + spm.removeToggleSensorPrivacyListener(this); } -bool SensorService::isMicSensorPrivacyEnabledForUid(uid_t uid) { - userid_t userId = multiuser_get_user_id(uid); - if (mMicSensorPrivacyPolicies.find(userId) == mMicSensorPrivacyPolicies.end()) { - sp userPolicy = new SensorPrivacyPolicy(this); - if (userPolicy->registerSelfForIndividual(userId) != OK) { - return false; +binder::Status SensorService::MicrophonePrivacyPolicy::onSensorPrivacyChanged(int toggleType __unused, + int sensor, bool enabled) { + if (sensor != SensorPrivacyManager::TOGGLE_SENSOR_MICROPHONE) { + return binder::Status::ok(); + } + mSensorPrivacyEnabled = enabled; + sp service = mService.promote(); + + if (service != nullptr) { + if (enabled) { + service->capRates(); + } else { + service->uncapRates(); } - mMicSensorPrivacyPolicies[userId] = userPolicy; } - return mMicSensorPrivacyPolicies[userId]->isSensorPrivacyEnabled(); + return binder::Status::ok(); } SensorService::ConnectionSafeAutolock::ConnectionSafeAutolock( diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index b009829ed6..7194db3275 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -289,22 +289,32 @@ private: class SensorPrivacyPolicy : public hardware::BnSensorPrivacyListener { public: explicit SensorPrivacyPolicy(wp service) - : mService(service), mIsIndividualMic(false), mUserId(0) {} + : mService(service) {} void registerSelf(); void unregisterSelf(); - status_t registerSelfForIndividual(int userId); - bool isSensorPrivacyEnabled(); - binder::Status onSensorPrivacyChanged(bool enabled); + binder::Status onSensorPrivacyChanged(int toggleType, int sensor, + bool enabled); - private: + protected: + std::atomic_bool mSensorPrivacyEnabled; wp mService; + + private: Mutex mSensorPrivacyLock; - std::atomic_bool mSensorPrivacyEnabled; - bool mIsIndividualMic; - userid_t mUserId; + }; + + class MicrophonePrivacyPolicy : public SensorPrivacyPolicy { + public: + explicit MicrophonePrivacyPolicy(wp service) + : SensorPrivacyPolicy(service) {} + void registerSelf(); + void unregisterSelf(); + + binder::Status onSensorPrivacyChanged(int toggleType, int sensor, + bool enabled); }; // A class automatically clearing and restoring binder caller identity inside @@ -444,9 +454,9 @@ private: void enableAllSensorsLocked(ConnectionSafeAutolock* connLock); // Caps active direct connections (when the mic toggle is flipped to on) - void capRates(userid_t userId); + void capRates(); // Removes the capped rate on active direct connections (when the mic toggle is flipped to off) - void uncapRates(userid_t userId); + void uncapRates(); static inline bool isAudioServerOrSystemServerUid(uid_t uid) { return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER; @@ -497,10 +507,7 @@ private: static Mutex sPackageTargetVersionLock; static String16 sSensorInterfaceDescriptorPrefix; - // Map from user to SensorPrivacyPolicy - std::map> mMicSensorPrivacyPolicies; - // Checks if the mic sensor privacy is enabled for the uid - bool isMicSensorPrivacyEnabledForUid(uid_t uid); + sp mMicSensorPrivacyPolicy; // Keeps track of the handles of all proximity sensors in the system. std::vector mProxSensorHandles; -- cgit v1.2.3-59-g8ed1b From b9c5a77a31d16212d87335abd5909d4d78a2b981 Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Fri, 4 Feb 2022 21:17:37 -0800 Subject: Use VsyncEventData in DisplayEventReceiver::Event. Clean-up that re-uses VsyncEventData so it's easier to maintain. The ParcelableVsyncEventData is used in AIDL. It is separated from VsyncEventData because of the union in DisplayEventReceiver::Event and Parcelable has non-trivial constructors. Bug: 218563993 Test: atest ChoreographerNativeTest Test: atest libsurfaceflinger_unittest Test: atest libgui_test Change-Id: I3ebeb1c7826300c27c4a12d4dba6fbd16305e9e1 --- libs/gui/DisplayEventDispatcher.cpp | 21 +--- libs/gui/DisplayEventReceiver.cpp | 7 +- libs/gui/VsyncEventData.cpp | 60 +++++------- .../aidl/android/gui/IDisplayEventConnection.aidl | 4 +- .../aidl/android/gui/ParcelableVsyncEventData.aidl | 19 ++++ libs/gui/aidl/android/gui/VsyncEventData.aidl | 19 ---- libs/gui/include/gui/DisplayEventReceiver.h | 14 +-- libs/gui/include/gui/VsyncEventData.h | 56 +++++------ libs/gui/tests/DisplayEventStructLayout_test.cpp | 30 +++++- libs/gui/tests/VsyncEventData_test.cpp | 53 ++++------ libs/nativedisplay/AChoreographer.cpp | 23 ++--- services/surfaceflinger/Scheduler/EventThread.cpp | 109 +++++++++------------ services/surfaceflinger/Scheduler/EventThread.h | 20 ++-- services/surfaceflinger/Scheduler/MessageQueue.cpp | 3 +- .../tests/DisplayEventReceiver_test.cpp | 15 +-- .../surfaceflinger/tests/LayerCallback_test.cpp | 5 +- .../tests/unittests/DispSyncSourceTest.cpp | 10 +- .../tests/unittests/EventThreadTest.cpp | 65 ++++++------ 18 files changed, 239 insertions(+), 294 deletions(-) create mode 100644 libs/gui/aidl/android/gui/ParcelableVsyncEventData.aidl delete mode 100644 libs/gui/aidl/android/gui/VsyncEventData.aidl diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp index 26db59bcff..39d380d9e1 100644 --- a/libs/gui/DisplayEventDispatcher.cpp +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -126,7 +126,7 @@ int DisplayEventDispatcher::handleEvent(int, int events, void*) { ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64 ", displayId=%s, count=%d, vsyncId=%" PRId64, this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount, - vsyncEventData.id); + vsyncEventData.preferredVsyncId()); mWaitingForVsync = false; mLastVsyncCount = vsyncCount; dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData); @@ -146,18 +146,6 @@ int DisplayEventDispatcher::handleEvent(int, int events, void*) { return 1; // keep the callback } -void DisplayEventDispatcher::populateFrameTimelines(const DisplayEventReceiver::Event& event, - VsyncEventData* outVsyncEventData) const { - for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { - DisplayEventReceiver::Event::VSync::FrameTimeline receiverTimeline = - event.vsync.frameTimelines[i]; - outVsyncEventData->frameTimelines[i] = - VsyncEventData::FrameTimeline(receiverTimeline.vsyncId, - receiverTimeline.deadlineTimestamp, - receiverTimeline.expectedVSyncTimestamp); - } -} - bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, uint32_t* outCount, @@ -178,12 +166,7 @@ bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, *outTimestamp = ev.header.timestamp; *outDisplayId = ev.header.displayId; *outCount = ev.vsync.count; - outVsyncEventData->id = ev.vsync.vsyncId; - outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp; - outVsyncEventData->frameInterval = ev.vsync.frameInterval; - outVsyncEventData->preferredFrameTimelineIndex = - ev.vsync.preferredFrameTimelineIndex; - populateFrameTimelines(ev, outVsyncEventData); + *outVsyncEventData = ev.vsync.vsyncData; break; case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected); diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp index 36e7d80d5e..ec0be87340 100644 --- a/libs/gui/DisplayEventReceiver.cpp +++ b/libs/gui/DisplayEventReceiver.cpp @@ -80,15 +80,14 @@ status_t DisplayEventReceiver::requestNextVsync() { return NO_INIT; } -status_t DisplayEventReceiver::getLatestVsyncEventData(VsyncEventData* outVsyncEventData) const { +status_t DisplayEventReceiver::getLatestVsyncEventData( + ParcelableVsyncEventData* outVsyncEventData) const { if (mEventConnection != nullptr) { - VsyncEventData vsyncEventData; - auto status = mEventConnection->getLatestVsyncEventData(&vsyncEventData); + auto status = mEventConnection->getLatestVsyncEventData(outVsyncEventData); if (!status.isOk()) { ALOGE("Failed to get latest vsync event data: %s", status.exceptionMessage().c_str()); return status.transactionError(); } - *outVsyncEventData = vsyncEventData; return NO_ERROR; } return NO_INIT; diff --git a/libs/gui/VsyncEventData.cpp b/libs/gui/VsyncEventData.cpp index aad81d0198..23f0921e99 100644 --- a/libs/gui/VsyncEventData.cpp +++ b/libs/gui/VsyncEventData.cpp @@ -23,52 +23,46 @@ namespace android::gui { -status_t VsyncEventData::readFromParcel(const Parcel* parcel) { +int64_t VsyncEventData::preferredVsyncId() const { + return frameTimelines[preferredFrameTimelineIndex].vsyncId; +} + +int64_t VsyncEventData::preferredDeadlineTimestamp() const { + return frameTimelines[preferredFrameTimelineIndex].deadlineTimestamp; +} + +int64_t VsyncEventData::preferredExpectedPresentationTime() const { + return frameTimelines[preferredFrameTimelineIndex].expectedPresentationTime; +} + +status_t ParcelableVsyncEventData::readFromParcel(const Parcel* parcel) { if (parcel == nullptr) { ALOGE("%s: Null parcel", __func__); return BAD_VALUE; } - SAFE_PARCEL(parcel->readInt64, &id) - SAFE_PARCEL(parcel->readInt64, &deadlineTimestamp); - SAFE_PARCEL(parcel->readInt64, &frameInterval); + SAFE_PARCEL(parcel->readInt64, &vsync.frameInterval); uint64_t uintPreferredFrameTimelineIndex; SAFE_PARCEL(parcel->readUint64, &uintPreferredFrameTimelineIndex); - preferredFrameTimelineIndex = static_cast(uintPreferredFrameTimelineIndex); - - std::vector timelines; - SAFE_PARCEL(parcel->readParcelableVector, &timelines); - std::copy_n(timelines.begin(), timelines.size(), frameTimelines.begin()); + vsync.preferredFrameTimelineIndex = static_cast(uintPreferredFrameTimelineIndex); - return OK; -} -status_t VsyncEventData::writeToParcel(Parcel* parcel) const { - SAFE_PARCEL(parcel->writeInt64, id) - SAFE_PARCEL(parcel->writeInt64, deadlineTimestamp); - SAFE_PARCEL(parcel->writeInt64, frameInterval); - SAFE_PARCEL(parcel->writeUint64, preferredFrameTimelineIndex); - SAFE_PARCEL(parcel->writeParcelableVector, - std::vector(frameTimelines.begin(), frameTimelines.end())); - - return OK; -} -status_t VsyncEventData::FrameTimeline::readFromParcel(const Parcel* parcel) { - if (parcel == nullptr) { - ALOGE("%s: Null parcel", __func__); - return BAD_VALUE; + for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { + SAFE_PARCEL(parcel->readInt64, &vsync.frameTimelines[i].vsyncId); + SAFE_PARCEL(parcel->readInt64, &vsync.frameTimelines[i].deadlineTimestamp); + SAFE_PARCEL(parcel->readInt64, &vsync.frameTimelines[i].expectedPresentationTime); } - SAFE_PARCEL(parcel->readInt64, &id) - SAFE_PARCEL(parcel->readInt64, &deadlineTimestamp); - SAFE_PARCEL(parcel->readInt64, &expectedPresentTime); - return OK; } -status_t VsyncEventData::FrameTimeline::writeToParcel(Parcel* parcel) const { - SAFE_PARCEL(parcel->writeInt64, id); - SAFE_PARCEL(parcel->writeInt64, deadlineTimestamp); - SAFE_PARCEL(parcel->writeInt64, expectedPresentTime); +status_t ParcelableVsyncEventData::writeToParcel(Parcel* parcel) const { + SAFE_PARCEL(parcel->writeInt64, vsync.frameInterval); + SAFE_PARCEL(parcel->writeUint64, vsync.preferredFrameTimelineIndex); + for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { + SAFE_PARCEL(parcel->writeInt64, vsync.frameTimelines[i].vsyncId); + SAFE_PARCEL(parcel->writeInt64, vsync.frameTimelines[i].deadlineTimestamp); + SAFE_PARCEL(parcel->writeInt64, vsync.frameTimelines[i].expectedPresentationTime); + } return OK; } diff --git a/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl b/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl index e9a6a0c642..9781ca96f4 100644 --- a/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl +++ b/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl @@ -17,7 +17,7 @@ package android.gui; import android.gui.BitTube; -import android.gui.VsyncEventData; +import android.gui.ParcelableVsyncEventData; /** @hide */ interface IDisplayEventConnection { @@ -43,5 +43,5 @@ interface IDisplayEventConnection { /* * getLatestVsyncEventData() gets the latest vsync event data. */ - VsyncEventData getLatestVsyncEventData(); + ParcelableVsyncEventData getLatestVsyncEventData(); } diff --git a/libs/gui/aidl/android/gui/ParcelableVsyncEventData.aidl b/libs/gui/aidl/android/gui/ParcelableVsyncEventData.aidl new file mode 100644 index 0000000000..ba76671f8f --- /dev/null +++ b/libs/gui/aidl/android/gui/ParcelableVsyncEventData.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.gui; + +parcelable ParcelableVsyncEventData cpp_header "gui/VsyncEventData.h"; diff --git a/libs/gui/aidl/android/gui/VsyncEventData.aidl b/libs/gui/aidl/android/gui/VsyncEventData.aidl deleted file mode 100644 index 7343515d25..0000000000 --- a/libs/gui/aidl/android/gui/VsyncEventData.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.gui; - -parcelable VsyncEventData cpp_header "gui/VsyncEventData.h"; diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index 4e04db3cde..ddc109e52a 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -35,6 +35,7 @@ namespace android { // ---------------------------------------------------------------------------- using gui::IDisplayEventConnection; +using gui::ParcelableVsyncEventData; using gui::VsyncEventData; namespace gui { @@ -76,16 +77,7 @@ public: struct VSync { uint32_t count; - nsecs_t expectedVSyncTimestamp __attribute__((aligned(8))); - nsecs_t deadlineTimestamp __attribute__((aligned(8))); - nsecs_t frameInterval __attribute__((aligned(8))); - int64_t vsyncId; - size_t preferredFrameTimelineIndex __attribute__((aligned(8))); - struct FrameTimeline { - nsecs_t expectedVSyncTimestamp __attribute__((aligned(8))); - nsecs_t deadlineTimestamp __attribute__((aligned(8))); - int64_t vsyncId; - } frameTimelines[VsyncEventData::kFrameTimelinesLength]; + VsyncEventData vsyncData; }; struct Hotplug { @@ -175,7 +167,7 @@ public: /** * getLatestVsyncEventData() gets the latest vsync event data. */ - status_t getLatestVsyncEventData(VsyncEventData* outVsyncEventData) const; + status_t getLatestVsyncEventData(ParcelableVsyncEventData* outVsyncEventData) const; private: sp mEventConnection; diff --git a/libs/gui/include/gui/VsyncEventData.h b/libs/gui/include/gui/VsyncEventData.h index abac61c334..8e99539fe9 100644 --- a/libs/gui/include/gui/VsyncEventData.h +++ b/libs/gui/include/gui/VsyncEventData.h @@ -21,52 +21,44 @@ #include namespace android::gui { -struct VsyncEventData : public Parcelable { +// Plain Old Data (POD) vsync data structure. For example, it can be easily used in the +// DisplayEventReceiver::Event union. +struct VsyncEventData { // Max amount of frame timelines is arbitrarily set to be reasonable. static constexpr int64_t kFrameTimelinesLength = 7; - // The Vsync Id corresponsing to this vsync event. This will be used to - // populate ISurfaceComposer::setFrameTimelineVsync and - // SurfaceComposerClient::setFrameTimelineVsync - // TODO(b/198191703): Remove when JNI DisplayEventReceiver uses frameTimelines array. - int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID; - - // The deadline in CLOCK_MONOTONIC that the app needs to complete its - // frame by (both on the CPU and the GPU) - // TODO(b/198191703): Remove when JNI DisplayEventReceiver uses frameTimelines array. - int64_t deadlineTimestamp = std::numeric_limits::max(); - // The current frame interval in ns when this frame was scheduled. - int64_t frameInterval = 0; + int64_t frameInterval; - struct FrameTimeline : public Parcelable { - FrameTimeline() = default; - FrameTimeline(int64_t id, int64_t deadlineTimestamp, int64_t expectedPresentTime) - : id(id), - deadlineTimestamp(deadlineTimestamp), - expectedPresentTime(expectedPresentTime) {} + // Index into the frameTimelines that represents the platform's preferred frame timeline. + uint32_t preferredFrameTimelineIndex; + struct alignas(8) FrameTimeline { // The Vsync Id corresponsing to this vsync event. This will be used to // populate ISurfaceComposer::setFrameTimelineVsync and // SurfaceComposerClient::setFrameTimelineVsync - int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID; + int64_t vsyncId; - // The deadline in CLOCK_MONOTONIC that the app needs to complete its - // frame by (both on the CPU and the GPU) - int64_t deadlineTimestamp = std::numeric_limits::max(); + // The deadline in CLOCK_MONOTONIC in nanos that the app needs to complete its + // frame by (both on the CPU and the GPU). + int64_t deadlineTimestamp; - // The anticipated Vsync present time. - int64_t expectedPresentTime = 0; + // The anticipated Vsync presentation time in nanos. + int64_t expectedPresentationTime; + } frameTimelines[kFrameTimelinesLength]; // Sorted possible frame timelines. - status_t readFromParcel(const Parcel*) override; - status_t writeToParcel(Parcel*) const override; - }; + // Gets the preferred frame timeline's vsync ID. + int64_t preferredVsyncId() const; - // Sorted possible frame timelines. - std::array frameTimelines; + // Gets the preferred frame timeline's deadline timestamp. + int64_t preferredDeadlineTimestamp() const; - // Index into the frameTimelines that represents the platform's preferred frame timeline. - size_t preferredFrameTimelineIndex = std::numeric_limits::max(); + // Gets the preferred frame timeline's expected vsync timestamp. + int64_t preferredExpectedPresentationTime() const; +}; + +struct ParcelableVsyncEventData : public Parcelable { + VsyncEventData vsync; status_t readFromParcel(const Parcel*) override; status_t writeToParcel(Parcel*) const override; diff --git a/libs/gui/tests/DisplayEventStructLayout_test.cpp b/libs/gui/tests/DisplayEventStructLayout_test.cpp index bcd39dbbf4..da88463d63 100644 --- a/libs/gui/tests/DisplayEventStructLayout_test.cpp +++ b/libs/gui/tests/DisplayEventStructLayout_test.cpp @@ -20,9 +20,10 @@ namespace android::test { #define CHECK_OFFSET(type, member, expected_offset) \ - static_assert((offsetof(type, member) == (expected_offset)), "") + static_assert((offsetof(type, member) == (expected_offset))) TEST(DisplayEventStructLayoutTest, TestEventAlignment) { + static_assert(std::is_pod::value); CHECK_OFFSET(DisplayEventReceiver::Event, vsync, 24); CHECK_OFFSET(DisplayEventReceiver::Event, hotplug, 24); CHECK_OFFSET(DisplayEventReceiver::Event, modeChange, 24); @@ -32,10 +33,29 @@ TEST(DisplayEventStructLayoutTest, TestEventAlignment) { CHECK_OFFSET(DisplayEventReceiver::Event::Header, timestamp, 16); CHECK_OFFSET(DisplayEventReceiver::Event::VSync, count, 0); - CHECK_OFFSET(DisplayEventReceiver::Event::VSync, expectedVSyncTimestamp, 8); - CHECK_OFFSET(DisplayEventReceiver::Event::VSync, deadlineTimestamp, 16); - CHECK_OFFSET(DisplayEventReceiver::Event::VSync, frameInterval, 24); - CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncId, 32); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameInterval, 8); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.preferredFrameTimelineIndex, 16); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameTimelines, 24); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameTimelines[0].vsyncId, 24); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameTimelines[0].deadlineTimestamp, + 32); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, + vsyncData.frameTimelines[0].expectedPresentationTime, 40); + // Also test the offsets of the last frame timeline. A loop is not used because the non-const + // index cannot be used in static_assert. + const int lastFrameTimelineOffset = /* Start of array */ 24 + + (VsyncEventData::kFrameTimelinesLength - 1) * /* Size of FrameTimeline */ 24; + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, + vsyncData.frameTimelines[VsyncEventData::kFrameTimelinesLength - 1].vsyncId, + lastFrameTimelineOffset); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, + vsyncData.frameTimelines[VsyncEventData::kFrameTimelinesLength - 1] + .deadlineTimestamp, + lastFrameTimelineOffset + 8); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, + vsyncData.frameTimelines[VsyncEventData::kFrameTimelinesLength - 1] + .expectedPresentationTime, + lastFrameTimelineOffset + 16); CHECK_OFFSET(DisplayEventReceiver::Event::Hotplug, connected, 0); diff --git a/libs/gui/tests/VsyncEventData_test.cpp b/libs/gui/tests/VsyncEventData_test.cpp index a670d42fe3..f114522951 100644 --- a/libs/gui/tests/VsyncEventData_test.cpp +++ b/libs/gui/tests/VsyncEventData_test.cpp @@ -22,54 +22,37 @@ namespace android { +using gui::ParcelableVsyncEventData; using gui::VsyncEventData; using FrameTimeline = gui::VsyncEventData::FrameTimeline; namespace test { -TEST(VsyncEventData, Parcelling) { - VsyncEventData data; - data.id = 123; - data.deadlineTimestamp = 456; - data.frameInterval = 789; - data.preferredFrameTimelineIndex = 1; - FrameTimeline timeline0 = FrameTimeline(1, 2, 3); - FrameTimeline timeline1 = FrameTimeline(4, 5, 6); - data.frameTimelines[0] = timeline0; - data.frameTimelines[1] = timeline1; +TEST(ParcelableVsyncEventData, Parcelling) { + ParcelableVsyncEventData data; + data.vsync.frameInterval = 789; + data.vsync.preferredFrameTimelineIndex = 1; + FrameTimeline timeline0 = FrameTimeline{1, 2, 3}; + FrameTimeline timeline1 = FrameTimeline{4, 5, 6}; + data.vsync.frameTimelines[0] = timeline0; + data.vsync.frameTimelines[1] = timeline1; Parcel p; data.writeToParcel(&p); p.setDataPosition(0); - VsyncEventData data2; + ParcelableVsyncEventData data2; data2.readFromParcel(&p); - ASSERT_EQ(data.id, data2.id); - ASSERT_EQ(data.deadlineTimestamp, data2.deadlineTimestamp); - ASSERT_EQ(data.frameInterval, data2.frameInterval); - ASSERT_EQ(data.preferredFrameTimelineIndex, data2.preferredFrameTimelineIndex); - for (int i = 0; i < data.frameTimelines.size(); i++) { - ASSERT_EQ(data.frameTimelines[i].id, data2.frameTimelines[i].id); - ASSERT_EQ(data.frameTimelines[i].deadlineTimestamp, - data2.frameTimelines[i].deadlineTimestamp); - ASSERT_EQ(data.frameTimelines[i].expectedPresentTime, - data2.frameTimelines[i].expectedPresentTime); + ASSERT_EQ(data.vsync.frameInterval, data2.vsync.frameInterval); + ASSERT_EQ(data.vsync.preferredFrameTimelineIndex, data2.vsync.preferredFrameTimelineIndex); + for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { + ASSERT_EQ(data.vsync.frameTimelines[i].vsyncId, data2.vsync.frameTimelines[i].vsyncId); + ASSERT_EQ(data.vsync.frameTimelines[i].deadlineTimestamp, + data2.vsync.frameTimelines[i].deadlineTimestamp); + ASSERT_EQ(data.vsync.frameTimelines[i].expectedPresentationTime, + data2.vsync.frameTimelines[i].expectedPresentationTime); } } -TEST(FrameTimeline, Parcelling) { - FrameTimeline timeline = FrameTimeline(1, 2, 3); - - Parcel p; - timeline.writeToParcel(&p); - p.setDataPosition(0); - - FrameTimeline timeline2; - timeline2.readFromParcel(&p); - ASSERT_EQ(timeline.id, timeline2.id); - ASSERT_EQ(timeline.deadlineTimestamp, timeline2.deadlineTimestamp); - ASSERT_EQ(timeline.expectedPresentTime, timeline2.expectedPresentTime); -} - } // namespace test } // namespace android diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index b182a4a6f1..3ce381b122 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -103,9 +103,7 @@ class Choreographer; struct ChoreographerFrameCallbackDataImpl { int64_t frameTimeNanos{0}; - std::array frameTimelines; - - size_t preferredFrameTimelineIndex; + VsyncEventData vsyncEventData; const Choreographer* choreographer; }; @@ -450,8 +448,7 @@ bool Choreographer::inCallback() const { ChoreographerFrameCallbackDataImpl Choreographer::createFrameCallbackData(nsecs_t timestamp) const { return {.frameTimeNanos = timestamp, - .preferredFrameTimelineIndex = mLastVsyncEventData.preferredFrameTimelineIndex, - .frameTimelines = mLastVsyncEventData.frameTimelines, + .vsyncEventData = mLastVsyncEventData, .choreographer = this}; } @@ -634,7 +631,7 @@ size_t AChoreographerFrameCallbackData_getFrameTimelinesLength( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - return frameCallbackData->frameTimelines.size(); + return VsyncEventData::kFrameTimelinesLength; } size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex( const AChoreographerFrameCallbackData* data) { @@ -642,7 +639,7 @@ size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - return frameCallbackData->preferredFrameTimelineIndex; + return frameCallbackData->vsyncEventData.preferredFrameTimelineIndex; } AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId( const AChoreographerFrameCallbackData* data, size_t index) { @@ -650,8 +647,8 @@ AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); - return frameCallbackData->frameTimelines[index].id; + LOG_ALWAYS_FATAL_IF(index >= VsyncEventData::kFrameTimelinesLength, "Index out of bounds"); + return frameCallbackData->vsyncEventData.frameTimelines[index].vsyncId; } int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos( const AChoreographerFrameCallbackData* data, size_t index) { @@ -659,8 +656,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); - return frameCallbackData->frameTimelines[index].expectedPresentTime; + LOG_ALWAYS_FATAL_IF(index >= VsyncEventData::kFrameTimelinesLength, "Index out of bounds"); + return frameCallbackData->vsyncEventData.frameTimelines[index].expectedPresentationTime; } int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos( const AChoreographerFrameCallbackData* data, size_t index) { @@ -668,8 +665,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); - return frameCallbackData->frameTimelines[index].deadlineTimestamp; + LOG_ALWAYS_FATAL_IF(index >= VsyncEventData::kFrameTimelinesLength, "Index out of bounds"); + return frameCallbackData->vsyncEventData.frameTimelines[index].deadlineTimestamp; } AChoreographer* AChoreographer_create() { diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 2d0da4643d..5ba8a1b449 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -87,9 +87,10 @@ std::string toString(const DisplayEventReceiver::Event& event) { to_string(event.header.displayId).c_str(), event.hotplug.connected ? "connected" : "disconnected"); case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: - return StringPrintf("VSync{displayId=%s, count=%u, expectedVSyncTimestamp=%" PRId64 "}", + return StringPrintf("VSync{displayId=%s, count=%u, expectedPresentationTime=%" PRId64 + "}", to_string(event.header.displayId).c_str(), event.vsync.count, - event.vsync.expectedVSyncTimestamp); + event.vsync.vsyncData.preferredExpectedPresentationTime()); case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE: return StringPrintf("ModeChanged{displayId=%s, modeId=%u}", to_string(event.header.displayId).c_str(), event.modeChange.modeId); @@ -107,13 +108,19 @@ DisplayEventReceiver::Event makeHotplug(PhysicalDisplayId displayId, nsecs_t tim } DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t timestamp, - uint32_t count, nsecs_t expectedVSyncTimestamp, + uint32_t count, nsecs_t expectedPresentationTime, nsecs_t deadlineTimestamp) { DisplayEventReceiver::Event event; event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp}; event.vsync.count = count; - event.vsync.expectedVSyncTimestamp = expectedVSyncTimestamp; - event.vsync.deadlineTimestamp = deadlineTimestamp; + event.vsync.vsyncData.preferredFrameTimelineIndex = 0; + // Temporarily store the current vsync information in frameTimelines[0], marked as + // platform-preferred. When the event is dispatched later, the frame interval at that time is + // used with this information to generate multiple frame timeline choices. + event.vsync.vsyncData.frameTimelines[0] = {.vsyncId = FrameTimelineInfo::INVALID_VSYNC_ID, + .deadlineTimestamp = deadlineTimestamp, + .expectedPresentationTime = + expectedPresentationTime}; return event; } @@ -186,9 +193,10 @@ binder::Status EventThreadConnection::requestNextVsync() { return binder::Status::ok(); } -binder::Status EventThreadConnection::getLatestVsyncEventData(VsyncEventData* outVsyncEventData) { +binder::Status EventThreadConnection::getLatestVsyncEventData( + ParcelableVsyncEventData* outVsyncEventData) { ATRACE_CALL(); - *outVsyncEventData = mEventThread->getLatestVsyncEventData(this); + outVsyncEventData->vsync = mEventThread->getLatestVsyncEventData(this); return binder::Status::ok(); } @@ -338,10 +346,16 @@ void EventThread::requestNextVsync(const sp& connection) VsyncEventData EventThread::getLatestVsyncEventData( const sp& connection) const { - nsecs_t frameInterval = mGetVsyncPeriodFunction(connection->mOwnerUid); VsyncEventData vsyncEventData; + nsecs_t frameInterval = mGetVsyncPeriodFunction(connection->mOwnerUid); vsyncEventData.frameInterval = frameInterval; - generateFrameTimeline(vsyncEventData, frameInterval, systemTime(SYSTEM_TIME_MONOTONIC)); + VSyncSource::VSyncData vsyncData; + { + std::lock_guard lock(mMutex); + vsyncData = mVSyncSource->getLatestVSyncData(); + } + generateFrameTimeline(vsyncEventData, frameInterval, systemTime(SYSTEM_TIME_MONOTONIC), + vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp); return vsyncEventData; } @@ -370,7 +384,7 @@ void EventThread::onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncDa LOG_FATAL_IF(!mVSyncState); mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count, - vsyncData.expectedVSyncTimestamp, + vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp)); mCondition.notify_all(); } @@ -518,7 +532,8 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, const sp& connection) const { const auto throttleVsync = [&] { return mThrottleVsyncCallback && - mThrottleVsyncCallback(event.vsync.expectedVSyncTimestamp, connection->mOwnerUid); + mThrottleVsyncCallback(event.vsync.vsyncData.preferredExpectedPresentationTime(), + connection->mOwnerUid); }; switch (event.header.type) { @@ -568,79 +583,49 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, } int64_t EventThread::generateToken(nsecs_t timestamp, nsecs_t deadlineTimestamp, - nsecs_t expectedVSyncTimestamp) const { + nsecs_t expectedPresentationTime) const { if (mTokenManager != nullptr) { return mTokenManager->generateTokenForPredictions( - {timestamp, deadlineTimestamp, expectedVSyncTimestamp}); + {timestamp, deadlineTimestamp, expectedPresentationTime}); } return FrameTimelineInfo::INVALID_VSYNC_ID; } -void EventThread::generateFrameTimeline( - nsecs_t frameInterval, nsecs_t timestamp, nsecs_t preferredExpectedVSyncTimestamp, - nsecs_t preferredDeadlineTimestamp, - std::function setPreferredFrameTimelineIndex, - std::function - setFrameTimeline) const { +void EventThread::generateFrameTimeline(VsyncEventData& outVsyncEventData, nsecs_t frameInterval, + nsecs_t timestamp, + nsecs_t preferredExpectedPresentationTime, + nsecs_t preferredDeadlineTimestamp) const { // Add 1 to ensure the preferredFrameTimelineIndex entry (when multiplier == 0) is included. for (int64_t multiplier = -VsyncEventData::kFrameTimelinesLength + 1, currentIndex = 0; currentIndex < VsyncEventData::kFrameTimelinesLength; multiplier++) { - nsecs_t deadline = preferredDeadlineTimestamp + multiplier * frameInterval; + nsecs_t deadlineTimestamp = preferredDeadlineTimestamp + multiplier * frameInterval; // Valid possible frame timelines must have future values. - if (deadline > timestamp) { + if (deadlineTimestamp > timestamp) { if (multiplier == 0) { - setPreferredFrameTimelineIndex(currentIndex); + outVsyncEventData.preferredFrameTimelineIndex = currentIndex; } - nsecs_t expectedVSyncTimestamp = - preferredExpectedVSyncTimestamp + multiplier * frameInterval; - setFrameTimeline(currentIndex, - generateToken(timestamp, deadline, expectedVSyncTimestamp), - expectedVSyncTimestamp, deadline); + nsecs_t expectedPresentationTime = + preferredExpectedPresentationTime + multiplier * frameInterval; + outVsyncEventData.frameTimelines[currentIndex] = + {.vsyncId = + generateToken(timestamp, deadlineTimestamp, expectedPresentationTime), + .deadlineTimestamp = deadlineTimestamp, + .expectedPresentationTime = expectedPresentationTime}; currentIndex++; } } } -void EventThread::generateFrameTimeline(DisplayEventReceiver::Event& event) const { - generateFrameTimeline( - event.vsync.frameInterval, event.header.timestamp, event.vsync.expectedVSyncTimestamp, - event.vsync.deadlineTimestamp, - [&](int index) { event.vsync.preferredFrameTimelineIndex = index; }, - [&](int64_t index, int64_t vsyncId, nsecs_t expectedVSyncTimestamp, - nsecs_t deadlineTimestamp) { - event.vsync.frameTimelines[index] = {.vsyncId = vsyncId, - .deadlineTimestamp = deadlineTimestamp, - .expectedVSyncTimestamp = - expectedVSyncTimestamp}; - }); -} - -void EventThread::generateFrameTimeline(VsyncEventData& out, const nsecs_t frameInterval, - const nsecs_t timestamp) const { - VSyncSource::VSyncData vsyncData; - { - std::lock_guard lock(mMutex); - vsyncData = mVSyncSource->getLatestVSyncData(); - } - generateFrameTimeline( - frameInterval, timestamp, vsyncData.expectedVSyncTimestamp, vsyncData.deadlineTimestamp, - [&](int index) { out.preferredFrameTimelineIndex = index; }, - [&](int64_t index, int64_t vsyncId, nsecs_t expectedVSyncTimestamp, - nsecs_t deadlineTimestamp) { - out.frameTimelines[index] = - VsyncEventData::FrameTimeline(vsyncId, deadlineTimestamp, - expectedVSyncTimestamp); - }); -} - void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event, const DisplayEventConsumers& consumers) { for (const auto& consumer : consumers) { DisplayEventReceiver::Event copy = event; if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { - copy.vsync.frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid); - generateFrameTimeline(copy); + const int64_t frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid); + copy.vsync.vsyncData.frameInterval = frameInterval; + generateFrameTimeline(copy.vsync.vsyncData, frameInterval, copy.header.timestamp, + event.vsync.vsyncData.preferredExpectedPresentationTime(), + event.vsync.vsyncData.preferredDeadlineTimestamp()); } switch (consumer->postEvent(copy)) { case NO_ERROR: diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index a858169e65..c406478c17 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -45,6 +45,7 @@ namespace frametimeline { class TokenManager; } // namespace frametimeline +using gui::ParcelableVsyncEventData; using gui::VsyncEventData; // --------------------------------------------------------------------------- @@ -66,7 +67,7 @@ class VSyncSource { public: class VSyncData { public: - nsecs_t expectedVSyncTimestamp; + nsecs_t expectedPresentationTime; nsecs_t deadlineTimestamp; }; @@ -99,7 +100,7 @@ public: binder::Status stealReceiveChannel(gui::BitTube* outChannel) override; binder::Status setVsyncRate(int rate) override; binder::Status requestNextVsync() override; // asynchronous - binder::Status getLatestVsyncEventData(VsyncEventData* outVsyncEventData) override; + binder::Status getLatestVsyncEventData(ParcelableVsyncEventData* outVsyncEventData) override; // Called in response to requestNextVsync. const ResyncCallback resyncCallback; @@ -217,17 +218,10 @@ private: void onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncData) override; int64_t generateToken(nsecs_t timestamp, nsecs_t deadlineTimestamp, - nsecs_t expectedVSyncTimestamp) const; - void generateFrameTimeline(DisplayEventReceiver::Event& event) const; - void generateFrameTimeline(VsyncEventData& out, const nsecs_t frameInterval, - const nsecs_t timestamp) const; - void generateFrameTimeline( - nsecs_t frameInterval, nsecs_t timestamp, nsecs_t preferredExpectedVSyncTimestamp, - nsecs_t preferredDeadlineTimestamp, - std::function setPreferredFrameTimelineIndex, - std::function - setFrameTimeline) const; + nsecs_t expectedPresentationTime) const; + void generateFrameTimeline(VsyncEventData& outVsyncEventData, nsecs_t frameInterval, + nsecs_t timestamp, nsecs_t preferredExpectedPresentationTime, + nsecs_t preferredDeadlineTimestamp) const; const std::unique_ptr mVSyncSource GUARDED_BY(mMutex); frametimeline::TokenManager* const mTokenManager; diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp index a020e2c834..712cd5bdf3 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.cpp +++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp @@ -191,7 +191,8 @@ void MessageQueue::injectorCallback() { for (int i = 0; i < n; i++) { if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { auto& vsync = buffer[i].vsync; - mHandler->dispatchFrame(vsync.vsyncId, vsync.expectedVSyncTimestamp); + mHandler->dispatchFrame(vsync.vsyncData.preferredVsyncId(), + vsync.vsyncData.preferredExpectedPresentationTime()); break; } } diff --git a/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp index 01adbc8962..0e54664f77 100644 --- a/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp +++ b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp @@ -28,23 +28,24 @@ public: TEST_F(DisplayEventReceiverTest, getLatestVsyncEventData) { const nsecs_t now = systemTime(); - VsyncEventData vsyncEventData; - EXPECT_EQ(NO_ERROR, mDisplayEventReceiver.getLatestVsyncEventData(&vsyncEventData)); + ParcelableVsyncEventData parcelableVsyncEventData; + EXPECT_EQ(NO_ERROR, mDisplayEventReceiver.getLatestVsyncEventData(&parcelableVsyncEventData)); + const VsyncEventData& vsyncEventData = parcelableVsyncEventData.vsync; EXPECT_NE(std::numeric_limits::max(), vsyncEventData.preferredFrameTimelineIndex); EXPECT_GT(vsyncEventData.frameTimelines[0].deadlineTimestamp, now) << "Deadline timestamp should be greater than frame time"; - for (size_t i = 0; i < vsyncEventData.frameTimelines.size(); i++) { - EXPECT_NE(FrameTimelineInfo::INVALID_VSYNC_ID, vsyncEventData.frameTimelines[i].id); - EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime, + for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { + EXPECT_NE(FrameTimelineInfo::INVALID_VSYNC_ID, vsyncEventData.frameTimelines[i].vsyncId); + EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime, vsyncEventData.frameTimelines[i].deadlineTimestamp) << "Expected vsync timestamp should be greater than deadline"; if (i > 0) { EXPECT_GT(vsyncEventData.frameTimelines[i].deadlineTimestamp, vsyncEventData.frameTimelines[i - 1].deadlineTimestamp) << "Deadline timestamp out of order for frame timeline " << i; - EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime, - vsyncEventData.frameTimelines[i - 1].expectedPresentTime) + EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime, + vsyncEventData.frameTimelines[i - 1].expectedPresentationTime) << "Expected vsync timestamp out of order for frame timeline " << i; } } diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp index 5c16feeda8..8a2305b365 100644 --- a/services/surfaceflinger/tests/LayerCallback_test.cpp +++ b/services/surfaceflinger/tests/LayerCallback_test.cpp @@ -141,11 +141,12 @@ public: continue; } - vsync = {event.vsync.vsyncId, event.vsync.expectedVSyncTimestamp}; + vsync = {event.vsync.vsyncData.preferredVsyncId(), + event.vsync.vsyncData.preferredExpectedPresentationTime()}; } EXPECT_GE(vsync.vsyncId, 1); - EXPECT_GT(event.vsync.expectedVSyncTimestamp, systemTime()); + EXPECT_GT(vsync.expectedPresentTime, systemTime()); return vsync; } diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp index 0b6b475222..ec27edac6e 100644 --- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp +++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp @@ -229,7 +229,7 @@ TEST_F(DispSyncSourceTest, waitForCallbacks) { ASSERT_TRUE(callbackData.has_value()); const auto [when, vsyncData] = callbackData.value(); EXPECT_EQ(when, - vsyncData.expectedVSyncTimestamp - mWorkDuration.count() - + vsyncData.expectedPresentationTime - mWorkDuration.count() - mReadyDuration.count()); } } @@ -261,7 +261,7 @@ TEST_F(DispSyncSourceTest, waitForCallbacksWithDurationChange) { ASSERT_TRUE(callbackData.has_value()); const auto [when, vsyncData] = callbackData.value(); EXPECT_EQ(when, - vsyncData.expectedVSyncTimestamp - mWorkDuration.count() - + vsyncData.expectedPresentationTime - mWorkDuration.count() - mReadyDuration.count()); } @@ -283,7 +283,7 @@ TEST_F(DispSyncSourceTest, waitForCallbacksWithDurationChange) { const auto callbackData = mVSyncEventCallRecorder.waitForCall(); ASSERT_TRUE(callbackData.has_value()); const auto [when, vsyncData] = callbackData.value(); - EXPECT_EQ(when, vsyncData.expectedVSyncTimestamp - newDuration.count()); + EXPECT_EQ(when, vsyncData.expectedPresentationTime - newDuration.count()); } EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1); @@ -307,9 +307,9 @@ TEST_F(DispSyncSourceTest, getLatestVsyncData) { const auto vsyncData = mDispSyncSource->getLatestVSyncData(); ASSERT_GT(vsyncData.deadlineTimestamp, now); - ASSERT_GT(vsyncData.expectedVSyncTimestamp, vsyncData.deadlineTimestamp); + ASSERT_GT(vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp); EXPECT_EQ(vsyncData.deadlineTimestamp, - vsyncData.expectedVSyncTimestamp - vsyncInternalDuration); + vsyncData.expectedPresentationTime - vsyncInternalDuration); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index cc0a40f74b..14d8f987b0 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -99,7 +99,7 @@ protected: nsecs_t expectedTimestamp, unsigned expectedCount); void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount); void expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp, - nsecs_t preferredDeadline); + VSyncSource::VSyncData preferredVsyncData); void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, bool expectedConnected); void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, @@ -252,40 +252,42 @@ void EventThreadTest::expectVsyncEventReceivedByConnection(nsecs_t expectedTimes expectedCount); } -void EventThreadTest::expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp, - nsecs_t preferredDeadline) { +void EventThreadTest::expectVsyncEventFrameTimelinesCorrect( + nsecs_t expectedTimestamp, VSyncSource::VSyncData preferredVsyncData) { auto args = mConnectionEventCallRecorder.waitForCall(); ASSERT_TRUE(args.has_value()) << " did not receive an event for timestamp " << expectedTimestamp; const auto& event = std::get<0>(args.value()); for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { - auto prediction = - mTokenManager->getPredictionsForToken(event.vsync.frameTimelines[i].vsyncId); + auto prediction = mTokenManager->getPredictionsForToken( + event.vsync.vsyncData.frameTimelines[i].vsyncId); EXPECT_TRUE(prediction.has_value()); - EXPECT_EQ(prediction.value().endTime, event.vsync.frameTimelines[i].deadlineTimestamp) + EXPECT_EQ(prediction.value().endTime, + event.vsync.vsyncData.frameTimelines[i].deadlineTimestamp) << "Deadline timestamp does not match cached value"; EXPECT_EQ(prediction.value().presentTime, - event.vsync.frameTimelines[i].expectedVSyncTimestamp) - << "Expected vsync timestamp does not match cached value"; + event.vsync.vsyncData.frameTimelines[i].expectedPresentationTime) + << "Expected vsync.vsyncData timestamp does not match cached value"; if (i > 0) { - EXPECT_GT(event.vsync.frameTimelines[i].deadlineTimestamp, - event.vsync.frameTimelines[i - 1].deadlineTimestamp) + EXPECT_GT(event.vsync.vsyncData.frameTimelines[i].deadlineTimestamp, + event.vsync.vsyncData.frameTimelines[i - 1].deadlineTimestamp) << "Deadline timestamp out of order for frame timeline " << i; - EXPECT_GT(event.vsync.frameTimelines[i].expectedVSyncTimestamp, - event.vsync.frameTimelines[i - 1].expectedVSyncTimestamp) - << "Expected vsync timestamp out of order for frame timeline " << i; + EXPECT_GT(event.vsync.vsyncData.frameTimelines[i].expectedPresentationTime, + event.vsync.vsyncData.frameTimelines[i - 1].expectedPresentationTime) + << "Expected vsync.vsyncData timestamp out of order for frame timeline " << i; } // Vsync ID order lines up with registration into test token manager. - EXPECT_EQ(i, event.vsync.frameTimelines[i].vsyncId) + EXPECT_EQ(i, event.vsync.vsyncData.frameTimelines[i].vsyncId) << "Vsync ID incorrect for frame timeline " << i; - if (i == event.vsync.preferredFrameTimelineIndex) { - EXPECT_EQ(event.vsync.frameTimelines[i].deadlineTimestamp, preferredDeadline) + if (i == event.vsync.vsyncData.preferredFrameTimelineIndex) { + EXPECT_EQ(event.vsync.vsyncData.frameTimelines[i].deadlineTimestamp, + preferredVsyncData.deadlineTimestamp) << "Preferred deadline timestamp incorrect" << i; - EXPECT_EQ(event.vsync.frameTimelines[i].expectedVSyncTimestamp, - event.vsync.expectedVSyncTimestamp) - << "Preferred expected vsync timestamp incorrect" << i; + EXPECT_EQ(event.vsync.vsyncData.frameTimelines[i].expectedPresentationTime, + preferredVsyncData.expectedPresentationTime) + << "Preferred expected vsync.vsyncData timestamp incorrect" << i; } } } @@ -397,16 +399,17 @@ TEST_F(EventThreadTest, requestNextVsyncEventFrameTimelinesCorrect) { // Use the received callback to signal a vsync event. // The interceptor should receive the event, as well as the connection. - mCallback->onVSyncEvent(123, {456, 789}); + VSyncSource::VSyncData vsyncData = {456, 789}; + mCallback->onVSyncEvent(123, vsyncData); expectInterceptCallReceived(123); - expectVsyncEventFrameTimelinesCorrect(123, 789); + expectVsyncEventFrameTimelinesCorrect(123, vsyncData); } TEST_F(EventThreadTest, getLatestVsyncEventData) { const nsecs_t now = systemTime(); const nsecs_t preferredDeadline = now + 10000000; - const nsecs_t preferredExpectedVSyncTimestamp = now + 20000000; - const VSyncSource::VSyncData preferredData = {preferredExpectedVSyncTimestamp, + const nsecs_t preferredExpectedPresentationTime = now + 20000000; + const VSyncSource::VSyncData preferredData = {preferredExpectedPresentationTime, preferredDeadline}; EXPECT_CALL(*mVSyncSource, getLatestVSyncData()).WillOnce(Return(preferredData)); @@ -415,14 +418,14 @@ TEST_F(EventThreadTest, getLatestVsyncEventData) { << "Deadline timestamp should be greater than frame time"; for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { auto prediction = - mTokenManager->getPredictionsForToken(vsyncEventData.frameTimelines[i].id); + mTokenManager->getPredictionsForToken(vsyncEventData.frameTimelines[i].vsyncId); EXPECT_TRUE(prediction.has_value()); EXPECT_EQ(prediction.value().endTime, vsyncEventData.frameTimelines[i].deadlineTimestamp) << "Deadline timestamp does not match cached value"; EXPECT_EQ(prediction.value().presentTime, - vsyncEventData.frameTimelines[i].expectedPresentTime) + vsyncEventData.frameTimelines[i].expectedPresentationTime) << "Expected vsync timestamp does not match cached value"; - EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime, + EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime, vsyncEventData.frameTimelines[i].deadlineTimestamp) << "Expected vsync timestamp should be greater than deadline"; @@ -430,19 +433,19 @@ TEST_F(EventThreadTest, getLatestVsyncEventData) { EXPECT_GT(vsyncEventData.frameTimelines[i].deadlineTimestamp, vsyncEventData.frameTimelines[i - 1].deadlineTimestamp) << "Deadline timestamp out of order for frame timeline " << i; - EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime, - vsyncEventData.frameTimelines[i - 1].expectedPresentTime) + EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime, + vsyncEventData.frameTimelines[i - 1].expectedPresentationTime) << "Expected vsync timestamp out of order for frame timeline " << i; } // Vsync ID order lines up with registration into test token manager. - EXPECT_EQ(i, vsyncEventData.frameTimelines[i].id) + EXPECT_EQ(i, vsyncEventData.frameTimelines[i].vsyncId) << "Vsync ID incorrect for frame timeline " << i; if (i == vsyncEventData.preferredFrameTimelineIndex) { EXPECT_EQ(vsyncEventData.frameTimelines[i].deadlineTimestamp, preferredDeadline) << "Preferred deadline timestamp incorrect" << i; - EXPECT_EQ(vsyncEventData.frameTimelines[i].expectedPresentTime, - preferredExpectedVSyncTimestamp) + EXPECT_EQ(vsyncEventData.frameTimelines[i].expectedPresentationTime, + preferredExpectedPresentationTime) << "Preferred expected vsync timestamp incorrect" << i; } } -- cgit v1.2.3-59-g8ed1b From c40dff533dd842bf6fae21c05eea472be7106ba2 Mon Sep 17 00:00:00 2001 From: Samiul Islam Date: Fri, 14 Jan 2022 16:24:48 +0000 Subject: Create supplemental data directories when app data is created Supplemental data is closely related to app data, as such we want their creation to happen at the same time. Owner of the these data will be the supplemental process instead of the app. The root directory for supplemental data is /data/misc_{ce,de}//supplemental. This directory will be created by vold when user is created. Installd is responsible for creating app level directories under the root, e.g, /data/misc_ce/0/supplemental/. We also need code level directory under the app direcotory, but that will be done with a separate API. CreateAppData is responsible for things at app level, so we will be maintaining the same level of abstraction. Instlld will also create the shared directory under the app-level directory, e.g, /data/misc_ce/0/supplemental//shared and `cache` and `code_cache` directory under the `shared` directory. Supplemental data should be removed when app data is removed. This will be done in follow up Cls too. Some of the public APIs of installd service was not being used by anybody else, so made them private. Bug: 211763739 Bug: 217543371 Test: atest installd_service_test:AppSupplementalDataTest Ignore-AOSP-First: Feature is being developed in internal branch Change-Id: I966c76b032821610293c53ba875e2800a5ce4804 --- cmds/installd/InstalldNativeService.cpp | 77 +++++++++++++++- cmds/installd/InstalldNativeService.h | 23 +++-- cmds/installd/tests/installd_service_test.cpp | 125 +++++++++++++++++++++++++- cmds/installd/tests/installd_utils_test.cpp | 34 +++++++ cmds/installd/utils.cpp | 37 ++++++++ cmds/installd/utils.h | 7 ++ 6 files changed, 289 insertions(+), 14 deletions(-) diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index f0dcd02920..b4e4133c1b 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -18,13 +18,9 @@ #define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER -#include #include -#include #include -#include #include -#include #include #include #include @@ -40,6 +36,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include @@ -720,6 +721,74 @@ binder::Status InstalldNativeService::createAppDataLocked( return error("Failed to prepare profiles for " + packageName); } } + + { + auto status = createAppDirectoryForSupplementalData(uuid, packageName, userId, appId, + previousAppId, seInfo, flags); + if (!status.isOk()) { + return status; + } + } + + return ok(); +} + +/** + * Responsible for creating /data/user/0/supplemental/ directory and other + * app level sub directories, such as ./shared + */ +binder::Status InstalldNativeService::createAppDirectoryForSupplementalData( + const std::optional& uuid, const std::string& packageName, int32_t userId, + int32_t appId, int32_t previousAppId, const std::string& seInfo, int32_t flags) { + int32_t supplementalUid = multiuser_get_supplemental_uid(userId, appId); + if (supplementalUid == -1) { + // There no valid supplemental process for this app. Skip creation of data directory + return ok(); + } + + // TODO(b/211763739): what if uuid is not nullptr or TEST? + const char* uuid_ = uuid ? uuid->c_str() : nullptr; + + constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE}; + for (int i = 0; i < 2; i++) { + int currentFlag = storageFlags[i]; + if ((flags & currentFlag) == 0) { + continue; + } + bool isCeData = (currentFlag == FLAG_STORAGE_CE); + + // /data/misc_{ce,de}//supplemental directory gets created by vold + // during user creation + + // Prepare the app directory + auto appPath = create_data_misc_supplemental_package_path(uuid_, isCeData, userId, + packageName.c_str()); + if (prepare_app_dir(appPath, 0751, AID_SYSTEM)) { + return error("Failed to prepare " + appPath); + } + + // Now prepare the shared directory which will be accessible by all codes + auto sharedPath = create_data_misc_supplemental_shared_path(uuid_, isCeData, userId, + packageName.c_str()); + + int32_t previousSupplementalUid = multiuser_get_supplemental_uid(userId, previousAppId); + int32_t cacheGid = multiuser_get_cache_gid(userId, appId); + if (cacheGid == -1) { + return exception(binder::Status::EX_ILLEGAL_STATE, + StringPrintf("cacheGid cannot be -1 for supplemental data")); + } + auto status = createAppDataDirs(sharedPath, supplementalUid, &previousSupplementalUid, + cacheGid, seInfo, 0700); + if (!status.isOk()) { + return status; + } + + // TODO(b/211763739): We also need to handle art profile creations + + // TODO(b/211763739): And return the CE inode of the supplemental root directory and + // app directory under it so we can clear contents while CE storage is locked + } + return ok(); } diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index ecc60b5448..6b4ba1f72e 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -47,14 +47,9 @@ public: int32_t flags); binder::Status createAppData(const std::optional& uuid, - const std::string& packageName, int32_t userId, int32_t flags, int32_t appId, - int32_t previousAppId, const std::string& seInfo, int32_t targetSdkVersion, - int64_t* _aidl_return); - binder::Status createAppDataLocked(const std::optional& uuid, - const std::string& packageName, int32_t userId, - int32_t flags, int32_t appId, int32_t previousAppId, - const std::string& seInfo, int32_t targetSdkVersion, - int64_t* _aidl_return); + const std::string& packageName, int32_t userId, int32_t flags, + int32_t appId, int32_t previousAppId, const std::string& seInfo, + int32_t targetSdkVersion, int64_t* _aidl_return); binder::Status createAppData( const android::os::CreateAppDataArgs& args, @@ -203,6 +198,18 @@ private: std::unordered_map mCacheQuotas; std::string findDataMediaPath(const std::optional& uuid, userid_t userid); + + binder::Status createAppDataLocked(const std::optional& uuid, + const std::string& packageName, int32_t userId, + int32_t flags, int32_t appId, int32_t previousAppId, + const std::string& seInfo, int32_t targetSdkVersion, + int64_t* _aidl_return); + + binder::Status createAppDirectoryForSupplementalData(const std::optional& uuid, + const std::string& packageName, + int32_t userId, int32_t appId, + int32_t previousAppId, + const std::string& seInfo, int32_t flags); }; } // namespace installd diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp index 806797f230..ce9bd1c15d 100644 --- a/cmds/installd/tests/installd_service_test.cpp +++ b/cmds/installd/tests/installd_service_test.cpp @@ -74,8 +74,14 @@ std::string get_package_name(uid_t uid) { } namespace installd { -constexpr const char* kTestUuid = "TEST"; -constexpr const char* kTestPath = "/data/local/tmp/user/0"; +static constexpr const char* kTestUuid = "TEST"; +static constexpr const char* kTestPath = "/data/local/tmp/user/0"; +static constexpr const uid_t kSystemUid = 1000; +static constexpr const int32_t kTestUserId = 0; +static constexpr const uid_t kTestAppId = 19999; + +const gid_t kTestAppUid = multiuser_get_uid(kTestUserId, kTestAppId); +const uid_t kTestAppSupplementalUid = multiuser_get_supplemental_uid(kTestUserId, kTestAppId); #define FLAG_FORCE InstalldNativeService::FLAG_FORCE @@ -930,5 +936,120 @@ TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot_WrongVolumeUuid) { "com.foo", 10000, "", 0, 41, FLAG_STORAGE_DE)); } +class AppSupplementalDataTest : public testing::Test { +public: + void CheckFileAccess(const std::string& path, uid_t uid, mode_t mode) { + const auto fullPath = "/data/local/tmp/" + path; + ASSERT_TRUE(exists(fullPath.c_str())) << "For path: " << fullPath; + struct stat st; + ASSERT_EQ(0, stat(fullPath.c_str(), &st)); + ASSERT_EQ(uid, st.st_uid) << "For path: " << fullPath; + ASSERT_EQ(uid, st.st_gid) << "For path: " << fullPath; + ASSERT_EQ(mode, st.st_mode) << "For path: " << fullPath; + } + + bool exists(const char* path) { return ::access(path, F_OK) == 0; } + + // Creates a default CreateAppDataArgs object + android::os::CreateAppDataArgs createAppDataArgs() { + android::os::CreateAppDataArgs args; + args.uuid = kTestUuid; + args.packageName = "com.foo"; + args.userId = kTestUserId; + args.appId = kTestAppId; + args.seInfo = "default"; + args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE; + return args; + } + +protected: + InstalldNativeService* service; + + virtual void SetUp() { + setenv("ANDROID_LOG_TAGS", "*:v", 1); + android::base::InitLogging(nullptr); + + service = new InstalldNativeService(); + clearAppData(); + ASSERT_TRUE(mkdirs("/data/local/tmp/user/0", 0700)); + ASSERT_TRUE(mkdirs("/data/local/tmp/user_de/0", 0700)); + ASSERT_TRUE(mkdirs("/data/local/tmp/misc_ce/0/supplemental", 0700)); + ASSERT_TRUE(mkdirs("/data/local/tmp/misc_de/0/supplemental", 0700)); + + init_globals_from_data_and_root(); + } + + virtual void TearDown() { + delete service; + clearAppData(); + } + +private: + void clearAppData() { + ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user_de", true)); + ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/misc_ce", true)); + ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/misc_de", true)); + ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user_de", true)); + } +}; + +TEST_F(AppSupplementalDataTest, CreateAppData_CreatesSupplementalAppData) { + android::os::CreateAppDataResult result; + android::os::CreateAppDataArgs args = createAppDataArgs(); + args.packageName = "com.foo"; + args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE; + + // Create the app user data. + ASSERT_BINDER_SUCCESS(service->createAppData(args, &result)); + + CheckFileAccess("misc_ce/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751); + CheckFileAccess("misc_ce/0/supplemental/com.foo/shared", kTestAppSupplementalUid, + S_IFDIR | 0700); + CheckFileAccess("misc_ce/0/supplemental/com.foo/shared/cache", kTestAppSupplementalUid, + S_IFDIR | S_ISGID | 0771); + CheckFileAccess("misc_ce/0/supplemental/com.foo/shared/code_cache", kTestAppSupplementalUid, + S_IFDIR | S_ISGID | 0771); + + CheckFileAccess("misc_de/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751); + CheckFileAccess("misc_de/0/supplemental/com.foo/shared", kTestAppSupplementalUid, + S_IFDIR | 0700); + CheckFileAccess("misc_de/0/supplemental/com.foo/shared/cache", kTestAppSupplementalUid, + S_IFDIR | S_ISGID | 0771); + CheckFileAccess("misc_de/0/supplemental/com.foo/shared/code_cache", kTestAppSupplementalUid, + S_IFDIR | S_ISGID | 0771); +} + +TEST_F(AppSupplementalDataTest, CreateAppData_CreatesSupplementalAppData_WithoutDeFlag) { + android::os::CreateAppDataResult result; + android::os::CreateAppDataArgs args = createAppDataArgs(); + args.packageName = "com.foo"; + args.flags = FLAG_STORAGE_CE; + + // Create the app user data. + ASSERT_BINDER_SUCCESS(service->createAppData(args, &result)); + + // Only CE paths should exist + CheckFileAccess("misc_ce/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751); + + // DE paths should not exist + ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/supplemental/com.foo")); +} + +TEST_F(AppSupplementalDataTest, CreateAppData_CreatesSupplementalAppData_WithoutCeFlag) { + android::os::CreateAppDataResult result; + android::os::CreateAppDataArgs args = createAppDataArgs(); + args.packageName = "com.foo"; + args.flags = FLAG_STORAGE_DE; + + // Create the app user data. + ASSERT_BINDER_SUCCESS(service->createAppData(args, &result)); + + // CE paths should not exist + ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/supplemental/com.foo")); + + // Only DE paths should exist + CheckFileAccess("misc_de/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751); +} + } // namespace installd } // namespace android diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp index ed87b672ce..cf942feea6 100644 --- a/cmds/installd/tests/installd_utils_test.cpp +++ b/cmds/installd/tests/installd_utils_test.cpp @@ -638,5 +638,39 @@ TEST_F(UtilsTest, TestCreateDirIfNeeded) { ASSERT_NE(0, create_dir_if_needed("/data/local/tmp/user/0/bar/baz", 0700)); } +TEST_F(UtilsTest, TestSupplementalDataPaths) { + // Ce data paths + EXPECT_EQ("/data/misc_ce/0/supplemental", + create_data_misc_supplemental_path(nullptr, /*isCeData=*/true, 0)); + EXPECT_EQ("/data/misc_ce/10/supplemental", + create_data_misc_supplemental_path(nullptr, true, 10)); + + EXPECT_EQ("/data/misc_ce/0/supplemental/com.foo", + create_data_misc_supplemental_package_path(nullptr, true, 0, "com.foo")); + EXPECT_EQ("/data/misc_ce/10/supplemental/com.foo", + create_data_misc_supplemental_package_path(nullptr, true, 10, "com.foo")); + + EXPECT_EQ("/data/misc_ce/0/supplemental/com.foo/shared", + create_data_misc_supplemental_shared_path(nullptr, true, 0, "com.foo")); + EXPECT_EQ("/data/misc_ce/10/supplemental/com.foo/shared", + create_data_misc_supplemental_shared_path(nullptr, true, 10, "com.foo")); + + // De data paths + EXPECT_EQ("/data/misc_de/0/supplemental", + create_data_misc_supplemental_path(nullptr, /*isCeData=*/false, 0)); + EXPECT_EQ("/data/misc_de/10/supplemental", + create_data_misc_supplemental_path(nullptr, false, 10)); + + EXPECT_EQ("/data/misc_de/0/supplemental/com.foo", + create_data_misc_supplemental_package_path(nullptr, false, 0, "com.foo")); + EXPECT_EQ("/data/misc_de/10/supplemental/com.foo", + create_data_misc_supplemental_package_path(nullptr, false, 10, "com.foo")); + + EXPECT_EQ("/data/misc_de/0/supplemental/com.foo/shared", + create_data_misc_supplemental_shared_path(nullptr, false, 0, "com.foo")); + EXPECT_EQ("/data/misc_de/10/supplemental/com.foo/shared", + create_data_misc_supplemental_shared_path(nullptr, false, 10, "com.foo")); +} + } // namespace installd } // namespace android diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index 8a00be9193..1afac576f9 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -194,6 +194,43 @@ std::string create_data_user_de_path(const char* volume_uuid, userid_t userid) { return StringPrintf("%s/user_de/%u", data.c_str(), userid); } +/** + * Create the path name where supplemental data for all apps will be stored. + * E.g. /data/misc_ce/0/supplemental + */ +std::string create_data_misc_supplemental_path(const char* uuid, bool isCeData, userid_t user) { + std::string data(create_data_path(uuid)); + if (isCeData) { + return StringPrintf("%s/misc_ce/%d/supplemental", data.c_str(), user); + } else { + return StringPrintf("%s/misc_de/%d/supplemental", data.c_str(), user); + } +} + +/** + * Create the path name where code data for all codes in a particular app will be stored. + * E.g. /data/misc_ce/0/supplemental/ + */ +std::string create_data_misc_supplemental_package_path(const char* volume_uuid, bool isCeData, + userid_t user, const char* package_name) { + check_package_name(package_name); + return StringPrintf("%s/%s", + create_data_misc_supplemental_path(volume_uuid, isCeData, user).c_str(), + package_name); +} + +/** + * Create the path name where shared code data for a particular app will be stored. + * E.g. /data/misc_ce/0/supplemental//shared + */ +std::string create_data_misc_supplemental_shared_path(const char* volume_uuid, bool isCeData, + userid_t user, const char* package_name) { + return StringPrintf("%s/shared", + create_data_misc_supplemental_package_path(volume_uuid, isCeData, user, + package_name) + .c_str()); +} + std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user) { return StringPrintf("%s/misc_ce/%u/rollback", create_data_path(volume_uuid).c_str(), user); } diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h index ffde56233e..a97c8360da 100644 --- a/cmds/installd/utils.h +++ b/cmds/installd/utils.h @@ -60,6 +60,13 @@ std::string create_data_user_de_package_path(const char* volume_uuid, std::string create_data_user_ce_package_path_as_user_link( const char* volume_uuid, userid_t userid, const char* package_name); +std::string create_data_misc_supplemental_path(const char* volume_uuid, bool isCeData, + userid_t userid); +std::string create_data_misc_supplemental_package_path(const char* volume_uuid, bool isCeData, + userid_t userid, const char* package_name); +std::string create_data_misc_supplemental_shared_path(const char* volume_uuid, bool isCeData, + userid_t userid, const char* package_name); + std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user); std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user); std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user, -- cgit v1.2.3-59-g8ed1b From 8576dd703e41f0d05a4f4635c675e1aedb77561a Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Fri, 11 Feb 2022 18:19:06 +0530 Subject: Add new NDK function definitions in input.h This CL adds 2 new functions to get ActionButton and Classification from a MotionEvent. Test: atest android.view.cts.MotionEventTest Bug: 213266814 Change-Id: Id264a5d110c6c65a7daae89194ab234f64832e13 --- include/android/input.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ include/input/Input.h | 8 +++----- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/include/android/input.h b/include/android/input.h index e6ad943f55..fb5e204450 100644 --- a/include/android/input.h +++ b/include/android/input.h @@ -807,6 +807,33 @@ enum { AMOTION_EVENT_TOOL_TYPE_PALM = 5, }; +/** + * Constants that identify different gesture classification types. + */ +enum { + /** + * Classification constant: None. + * + * No additional information is available about the current motion event stream. + */ + AMOTION_EVENT_CLASSIFICATION_NONE = 0, + /** + * Classification constant: Ambiguous gesture. + * + * The user's intent with respect to the current event stream is not yet determined. + * Gestural actions, such as scrolling, should be inhibited until the classification resolves + * to another value or the event stream ends. + */ + AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE = 1, + /** + * Classification constant: Deep press. + * + * The current event stream represents the user intentionally pressing harder on the screen. + * This classification type should be used to accelerate the long press behaviour. + */ + AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS = 2, +}; + /** * Input source masks. * @@ -1326,6 +1353,23 @@ float AMotionEvent_getHistoricalOrientation(const AInputEvent* motion_event, siz float AMotionEvent_getHistoricalAxisValue(const AInputEvent* motion_event, int32_t axis, size_t pointer_index, size_t history_index); +/** + * Get the action button for the motion event. Returns a valid action button when the + * event is associated with a button press or button release action. For other actions + * the return value is undefined. + */ +int32_t AMotionEvent_getActionButton(const AInputEvent* motion_event); + +/** + * Returns the classification for the current gesture. + * The classification may change as more events become available for the same gesture. + * + * @see #AMOTION_EVENT_CLASSIFICATION_NONE + * @see #AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE + * @see #AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS +*/ +int32_t AMotionEvent_getClassification(const AInputEvent* motion_event); + /** * Creates a native AInputEvent* object that is a copy of the specified Java * android.view.MotionEvent. The result may be used with generic and MotionEvent-specific diff --git a/include/input/Input.h b/include/input/Input.h index e421dee275..2837add22c 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -275,23 +275,21 @@ enum { /** * Classifications of the current gesture, if available. - * - * The following values must be kept in sync with MotionEvent.java */ enum class MotionClassification : uint8_t { /** * No classification is available. */ - NONE = 0, + NONE = AMOTION_EVENT_CLASSIFICATION_NONE, /** * Too early to classify the current gesture. Need more events. Look for changes in the * upcoming motion events. */ - AMBIGUOUS_GESTURE = 1, + AMBIGUOUS_GESTURE = AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE, /** * The current gesture likely represents a user intentionally exerting force on the touchscreen. */ - DEEP_PRESS = 2, + DEEP_PRESS = AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS, }; /** -- cgit v1.2.3-59-g8ed1b From 977e7c363bdd316019ecafa27f252ce305fd9d52 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Tue, 15 Feb 2022 04:55:52 -0800 Subject: SF: Configure input windows with the first input-enabled display We can have a situation where more than one DisplayDevice can receive input for a layer stack. In this situation, we don't have a clear way to distinguish which display we should use for input. We change the implemntation so that we use the first input-enabled display in mDisplays to configure the input windows. In the case where a display is mirrored using the same layer stack, this would help if the display we actually want to receive input is listed first. Bug: 219191788 Test: manual: Developer options > "Simulate secondary display" Change-Id: Ic9cfff75f0178f80decf6cf1ffd3ba81a766caa6 --- services/surfaceflinger/SurfaceFlinger.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ee1ea4040d..8e5f9f8985 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3281,15 +3281,15 @@ void SurfaceFlinger::buildWindowInfos(std::vector& outWindowInfos, continue; } - // There is more than one display for the layerStack. In this case, the display that is - // configured to receive input takes precedence. + // There is more than one display for the layerStack. In this case, the first display that + // is configured to receive input takes precedence. auto& details = it->second; - if (!display->receivesInput()) { + if (details.receivesInput) { + ALOGW_IF(display->receivesInput(), + "Multiple displays claim to accept input for the same layer stack: %u", + layerStackId); continue; } - ALOGE_IF(details.receivesInput, - "Multiple displays claim to accept input for the same layer stack: %u", - layerStackId); details.receivesInput = display->receivesInput(); details.isSecure = display->isSecure(); details.transform = std::move(transform); -- cgit v1.2.3-59-g8ed1b From 76bdecb09d6a124838edf8495ce90ef4dc0cc3c8 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Mon, 31 Jan 2022 11:14:15 -0800 Subject: Invert some InputConfig flags to simplify default behavior Invert NOT_TOUCH_MODAL to TOUCH_MODAL, and SPLIT_TOUCH to PREVENT_SPLITTING. Modal windows and windows that prevent splitting are exceptional behaviors, so we make sure that these show up when outputting flag values using ftl::Flags::string(). Bug: 216806304 Test: atest inputflinger_tests Change-Id: I7cadcc830f06ff0c63da3b61a1a7580cb031f0c2 --- libs/gui/WindowInfo.cpp | 2 +- libs/gui/include/gui/WindowInfo.h | 4 +- libs/gui/tests/EndToEndNativeInputTest.cpp | 3 - .../inputflinger/dispatcher/InputDispatcher.cpp | 5 +- .../inputflinger/tests/InputDispatcher_test.cpp | 105 +++------------------ services/surfaceflinger/Layer.cpp | 6 +- 6 files changed, 20 insertions(+), 105 deletions(-) diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index 2c25e7e2ac..80bd6389a0 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -47,7 +47,7 @@ bool WindowInfo::frameContainsPoint(int32_t x, int32_t y) const { } bool WindowInfo::supportsSplitTouch() const { - return inputConfig.test(InputConfig::SPLIT_TOUCH); + return !inputConfig.test(InputConfig::PREVENT_SPLITTING); } bool WindowInfo::isSpy() const { diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index 1b3419a25b..c8d49865f0 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -164,8 +164,8 @@ struct WindowInfo : public Parcelable { NOT_VISIBLE = 1 << 0, NOT_FOCUSABLE = 1 << 1, NOT_TOUCHABLE = 1 << 2, - NOT_TOUCH_MODAL = 1 << 3, - SPLIT_TOUCH = 1 << 4, + TOUCH_MODAL = 1 << 3, + PREVENT_SPLITTING = 1 << 4, DUPLICATE_TOUCH_TO_WALLPAPER = 1 << 5, IS_WALLPAPER = 1 << 6, PAUSE_DISPATCHING = 1 << 7, diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 1151aa3f0f..fcfe21bee2 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -268,9 +268,6 @@ private: mInputInfo.name = "Test info"; mInputInfo.dispatchingTimeout = 5s; mInputInfo.globalScaleFactor = 1.0; - mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCH_MODAL, true); - mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, false); - mInputInfo.touchableRegion.orSelf(Rect(0, 0, width, height)); InputApplicationInfo aInfo; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index a26256318a..f5aa45b66c 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -509,9 +509,8 @@ bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32 if (inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) && !windowCanInterceptTouch) { return false; } - const bool isModalWindow = !inputConfig.test(WindowInfo::InputConfig::NOT_FOCUSABLE) && - !inputConfig.test(WindowInfo::InputConfig::NOT_TOUCH_MODAL); - if (!isModalWindow && !windowInfo.touchableRegionContainsPoint(x, y)) { + if (!inputConfig.test(WindowInfo::InputConfig::TOUCH_MODAL) && + !windowInfo.touchableRegionContainsPoint(x, y)) { return false; } return true; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index da65e176e5..51ecf763a1 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1000,11 +1000,7 @@ public: mInfo.ownerPid = INJECTOR_PID; mInfo.ownerUid = INJECTOR_UID; mInfo.displayId = displayId; - setVisible(true); - setFocusable(false); - setDupTouchToWallpaper(false); - setPaused(false); - setTrustedOverlay(false); + mInfo.inputConfig = WindowInfo::InputConfig::NONE; } sp clone( @@ -1037,11 +1033,11 @@ public: } void setTouchModal(bool touchModal) { - mInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCH_MODAL, !touchModal); + mInfo.setInputConfig(WindowInfo::InputConfig::TOUCH_MODAL, touchModal); } - void setSplitTouch(bool splitTouch) { - mInfo.setInputConfig(WindowInfo::InputConfig::SPLIT_TOUCH, splitTouch); + void setPreventSplitting(bool preventSplitting) { + mInfo.setInputConfig(WindowInfo::InputConfig::PREVENT_SPLITTING, preventSplitting); } void setSlippery(bool slippery) { @@ -1567,19 +1563,15 @@ TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay } /** - * Calling setInputWindows once with FLAG_NOT_TOUCH_MODAL should not cause any issues. - * To ensure that window receives only events that were directly inside of it, add - * FLAG_NOT_TOUCH_MODAL. This will enforce using the touchableRegion of the input - * when finding touched windows. + * Calling setInputWindows once should not cause any issues. * This test serves as a sanity check for the next test, where setInputWindows is * called twice. */ -TEST_F(InputDispatcherTest, SetInputWindowOnce_SingleWindowTouch) { +TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) { std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); - window->setTouchModal(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -1593,16 +1585,12 @@ TEST_F(InputDispatcherTest, SetInputWindowOnce_SingleWindowTouch) { /** * Calling setInputWindows twice, with the same info, should not cause any issues. - * To ensure that window receives only events that were directly inside of it, add - * FLAG_NOT_TOUCH_MODAL. This will enforce using the touchableRegion of the input - * when finding touched windows. */ TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) { std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); - window->setTouchModal(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -1790,15 +1778,11 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { sp leftWindow = new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); leftWindow->setFrame(Rect(0, 0, 200, 200)); - leftWindow->setTouchModal(false); - leftWindow->setSplitTouch(true); leftWindow->setDupTouchToWallpaper(true); sp rightWindow = new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); rightWindow->setFrame(Rect(200, 0, 400, 200)); - rightWindow->setTouchModal(false); - rightWindow->setSplitTouch(true); rightWindow->setDupTouchToWallpaper(true); sp wallpaperWindow = @@ -1878,11 +1862,9 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { sp windowLeft = new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); windowLeft->setFrame(Rect(0, 0, 600, 800)); - windowLeft->setTouchModal(false); sp windowRight = new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); windowRight->setFrame(Rect(600, 0, 1200, 800)); - windowRight->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -1989,7 +1971,6 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { sp window = new FakeWindowHandle(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 1200, 800)); - window->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -2071,11 +2052,9 @@ TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) { sp windowLeft = new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); windowLeft->setFrame(Rect(0, 0, 600, 800)); - windowLeft->setTouchModal(false); sp windowRight = new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); windowRight->setFrame(Rect(600, 0, 1200, 800)); - windowRight->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -2181,14 +2160,12 @@ public: // Add two windows to the display. Their frames are represented in the display space. sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); - firstWindow->setTouchModal(false); firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform); addWindow(firstWindow); sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); - secondWindow->setTouchModal(false); secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform); addWindow(secondWindow); return {std::move(firstWindow), std::move(secondWindow)}; @@ -2331,8 +2308,10 @@ TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) { // Create a couple of windows sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); + firstWindow->setPreventSplitting(true); sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); + secondWindow->setPreventSplitting(true); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -2405,19 +2384,13 @@ INSTANTIATE_TEST_SUITE_P(TransferFunctionTests, TransferTouchFixture, TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { std::shared_ptr application = std::make_shared(); - // Create a non touch modal window that supports split touch sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setTouchModal(false); - firstWindow->setSplitTouch(true); - // Create a non touch modal window that supports split touch sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setTouchModal(false); - secondWindow->setSplitTouch(true); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -2479,19 +2452,13 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) { std::shared_ptr application = std::make_shared(); - // Create a non touch modal window that supports split touch sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setTouchModal(false); - firstWindow->setSplitTouch(true); - // Create a non touch modal window that supports split touch sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setTouchModal(false); - secondWindow->setSplitTouch(true); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -2556,26 +2523,21 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_CloneSurface) { sp firstWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInPrimary->setTouchModal(false); sp secondWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setTouchModal(false); sp mirrorWindowInPrimary = firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT); mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200)); - mirrorWindowInPrimary->setTouchModal(false); sp firstWindowInSecondary = firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInSecondary->setTouchModal(false); sp secondWindowInSecondary = secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setTouchModal(false); // Update window info, let it find window handle of second display first. mDispatcher->setInputWindows( @@ -2620,26 +2582,21 @@ TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) { sp firstWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInPrimary->setTouchModal(false); sp secondWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setTouchModal(false); sp mirrorWindowInPrimary = firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT); mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200)); - mirrorWindowInPrimary->setTouchModal(false); sp firstWindowInSecondary = firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInSecondary->setTouchModal(false); sp secondWindowInSecondary = secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setTouchModal(false); // Update window info, let it find window handle of second display first. mDispatcher->setInputWindows( @@ -2733,19 +2690,13 @@ TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) { TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) { std::shared_ptr application = std::make_shared(); - // Create first non touch modal window that supports split touch sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setTouchModal(false); - firstWindow->setSplitTouch(true); - // Create second non touch modal window that supports split touch sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setTouchModal(false); - secondWindow->setSplitTouch(true); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -3265,9 +3216,9 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) { std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); + window->setFocusable(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); - // Window is not focusable. mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); setFocusedWindow(window); @@ -3275,7 +3226,7 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) { ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(mDispatcher)) << "Inject key event should return InputEventInjectionResult::TIMED_OUT"; - // window is invalid, so it should not receive any input event. + // window is not focusable, so it should not receive any input event. window->assertNoEvents(); } @@ -3412,7 +3363,6 @@ TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) { sp slipperyExitWindow = new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); - slipperyExitWindow->setTouchModal(false); slipperyExitWindow->setSlippery(true); // Make sure this one overlaps the bottom window slipperyExitWindow->setFrame(Rect(25, 25, 75, 75)); @@ -4019,14 +3969,10 @@ class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest { mUnfocusedWindow = new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30)); - // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this - // window. - mUnfocusedWindow->setTouchModal(false); mFocusedWindow = new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); - mFocusedWindow->setTouchModal(false); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -4133,16 +4079,10 @@ class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest { std::make_shared(); mWindow1 = new FakeWindowHandle(application, mDispatcher, "Fake Window 1", ADISPLAY_ID_DEFAULT); - // Adding FLAG_NOT_TOUCH_MODAL otherwise all taps will go to the top most window. - // We also need FLAG_SPLIT_TOUCH or we won't be able to get touches for both windows. - mWindow1->setTouchModal(false); - mWindow1->setSplitTouch(true); mWindow1->setFrame(Rect(0, 0, 100, 100)); mWindow2 = new FakeWindowHandle(application, mDispatcher, "Fake Window 2", ADISPLAY_ID_DEFAULT, mWindow1->getToken()); - mWindow2->setTouchModal(false); - mWindow2->setSplitTouch(true); mWindow2->setFrame(Rect(100, 100, 200, 200)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}}); @@ -4339,9 +4279,6 @@ class InputDispatcherSingleWindowAnr : public InputDispatcherTest { mWindow->setFrame(Rect(0, 0, 30, 30)); mWindow->setDispatchingTimeout(30ms); mWindow->setFocusable(true); - // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this - // window. - mWindow->setTouchModal(false); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); @@ -4789,19 +4726,13 @@ class InputDispatcherMultiWindowAnr : public InputDispatcherTest { mUnfocusedWindow = new FakeWindowHandle(mApplication, mDispatcher, "Unfocused", ADISPLAY_ID_DEFAULT); mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30)); - // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this - // window. // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped - mUnfocusedWindow->setTouchModal(false); - mUnfocusedWindow->setSplitTouch(true); mUnfocusedWindow->setWatchOutsideTouch(true); mFocusedWindow = new FakeWindowHandle(mApplication, mDispatcher, "Focused", ADISPLAY_ID_DEFAULT); mFocusedWindow->setDispatchingTimeout(30ms); mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); - mFocusedWindow->setTouchModal(false); - mFocusedWindow->setSplitTouch(true); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); @@ -5910,11 +5841,9 @@ protected: mApp = std::make_shared(); mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); mWindow->setFrame(Rect(0, 0, 100, 100)); - mWindow->setTouchModal(false); mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT); mSecondWindow->setFrame(Rect(100, 0, 200, 100)); - mSecondWindow->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}}); @@ -6330,7 +6259,6 @@ public: new FakeWindowHandle(application, mDispatcher, name.c_str(), ADISPLAY_ID_DEFAULT); spy->setInputFeatures(WindowInfo::Feature::SPY); spy->setTrustedOverlay(true); - spy->setTouchModal(false); return spy; } @@ -6340,8 +6268,6 @@ public: sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocusable(true); - window->setTouchModal(false); - window->setSplitTouch(true); return window; } @@ -6515,7 +6441,6 @@ TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) { window->setOwnerInfo(12, 34); auto spy = createSpy(); spy->setWatchOutsideTouch(true); - spy->setTouchModal(false); spy->setOwnerInfo(56, 78); spy->setFrame(Rect{0, 0, 20, 20}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); @@ -6593,7 +6518,6 @@ TEST_F(InputDispatcherSpyWindowTest, CanPilferAfterWindowIsRemovedMidStream) { */ TEST_F(InputDispatcherSpyWindowTest, ContinuesToReceiveGestureAfterPilfer) { auto spy = createSpy(); - spy->setTouchModal(false); auto window = createForeground(); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); @@ -6728,14 +6652,11 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { * windows should be allowed to control split touch. */ TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) { - // Create a touch modal spy that spies on the entire display. - // This spy window does not set split touch. However, we still expect to split touches + // This spy window prevents touch splitting. However, we still expect to split touches // because a foreground window has not disabled splitting. auto spy = createSpy(); - spy->setTouchModal(true); - spy->setSplitTouch(false); + spy->setPreventSplitting(true); - // Create a non touch modal window that supports split touch. auto window = createForeground(); window->setFrame(Rect(0, 0, 100, 100)); @@ -6805,7 +6726,6 @@ public: overlay->setFocusable(false); overlay->setOwnerInfo(111, 111); overlay->setTouchable(false); - overlay->setSplitTouch(true); overlay->setInputFeatures(WindowInfo::Feature::INTERCEPTS_STYLUS); overlay->setTrustedOverlay(true); @@ -6816,7 +6736,6 @@ public: ADISPLAY_ID_DEFAULT); window->setFocusable(true); window->setOwnerInfo(222, 222); - window->setSplitTouch(true); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d0d79e9dd3..219c7164c1 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2159,8 +2159,8 @@ Rect Layer::getInputBounds() const { void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) { Rect tmpBounds = getInputBounds(); if (!tmpBounds.isValid()) { - info.inputConfig |= - WindowInfo::InputConfig::NOT_TOUCH_MODAL | WindowInfo::InputConfig::NOT_FOCUSABLE; + info.setInputConfig(WindowInfo::InputConfig::TOUCH_MODAL, false); + info.setInputConfig(WindowInfo::InputConfig::NOT_FOCUSABLE, true); info.touchableRegion.clear(); // A layer could have invalid input bounds and still expect to receive touch input if it has // replaceTouchableRegionWithCrop. For that case, the input transform needs to be calculated @@ -2307,7 +2307,7 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool disp mDrawingState.inputInfo.ownerUid = mOwnerUid; mDrawingState.inputInfo.ownerPid = mOwnerPid; mDrawingState.inputInfo.inputFeatures = WindowInfo::Feature::NO_INPUT_CHANNEL; - mDrawingState.inputInfo.inputConfig |= WindowInfo::InputConfig::NOT_TOUCH_MODAL; + mDrawingState.inputInfo.setInputConfig(WindowInfo::InputConfig::TOUCH_MODAL, false); mDrawingState.inputInfo.displayId = getLayerStack().id; } -- cgit v1.2.3-59-g8ed1b From 06349040a46db18701ddff7cdd87da22ee7ba27c Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Fri, 4 Feb 2022 09:19:17 -0800 Subject: Remove the concept of TOUCH_MODAL from input We remove modal windows from input. WM will configure modal windows itself using touchableRegion. Bug: 216806304 Test: atest inputflinger_tests Change-Id: I9593865213216b420ab9b5c5b853298f01dabcc6 --- libs/gui/include/gui/WindowInfo.h | 15 ++++++------- .../inputflinger/dispatcher/InputDispatcher.cpp | 3 +-- .../inputflinger/tests/InputDispatcher_test.cpp | 25 ---------------------- services/surfaceflinger/Layer.cpp | 2 -- 4 files changed, 8 insertions(+), 37 deletions(-) diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index c8d49865f0..b9bffaa6a0 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -164,18 +164,17 @@ struct WindowInfo : public Parcelable { NOT_VISIBLE = 1 << 0, NOT_FOCUSABLE = 1 << 1, NOT_TOUCHABLE = 1 << 2, - TOUCH_MODAL = 1 << 3, - PREVENT_SPLITTING = 1 << 4, - DUPLICATE_TOUCH_TO_WALLPAPER = 1 << 5, - IS_WALLPAPER = 1 << 6, - PAUSE_DISPATCHING = 1 << 7, + PREVENT_SPLITTING = 1 << 3, + DUPLICATE_TOUCH_TO_WALLPAPER = 1 << 4, + IS_WALLPAPER = 1 << 5, + PAUSE_DISPATCHING = 1 << 6, // This flag is set when the window is of a trusted type that is allowed to silently // overlay other windows for the purpose of implementing the secure views feature. // Trusted overlays, such as IME windows, can partly obscure other windows without causing // motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. - TRUSTED_OVERLAY = 1 << 8, - WATCH_OUTSIDE_TOUCH = 1 << 9, - SLIPPERY = 1 << 10, + TRUSTED_OVERLAY = 1 << 7, + WATCH_OUTSIDE_TOUCH = 1 << 8, + SLIPPERY = 1 << 9, // clang-format on }; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index f5aa45b66c..58c93036bb 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -509,8 +509,7 @@ bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32 if (inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) && !windowCanInterceptTouch) { return false; } - if (!inputConfig.test(WindowInfo::InputConfig::TOUCH_MODAL) && - !windowInfo.touchableRegionContainsPoint(x, y)) { + if (!windowInfo.touchableRegionContainsPoint(x, y)) { return false; } return true; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 51ecf763a1..ae8358aa5d 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1032,10 +1032,6 @@ public: mInfo.setInputConfig(WindowInfo::InputConfig::PAUSE_DISPATCHING, paused); } - void setTouchModal(bool touchModal) { - mInfo.setInputConfig(WindowInfo::InputConfig::TOUCH_MODAL, touchModal); - } - void setPreventSplitting(bool preventSplitting) { mInfo.setInputConfig(WindowInfo::InputConfig::PREVENT_SPLITTING, preventSplitting); } @@ -6411,27 +6407,6 @@ TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) { spy->consumeMotionDown(); } -/** - * A spy window that is a modal window will receive gestures outside of its frame and touchable - * region. - */ -TEST_F(InputDispatcherSpyWindowTest, ModalWindow) { - auto window = createForeground(); - auto spy = createSpy(); - // Our current policy dictates that modal windows must be focusable. - spy->setFocusable(true); - spy->setTouchModal(true); - spy->setFrame(Rect{0, 0, 20, 20}); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); - - // Inject an event outside the spy window's frame and touchable region. - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) - << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - window->consumeMotionDown(); - spy->consumeMotionDown(); -} - /** * A spy window can listen for touches outside its touchable region using the WATCH_OUTSIDE_TOUCHES * flag, but it will get zero-ed out coordinates if the foreground has a different owner. diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 219c7164c1..808109603f 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2159,7 +2159,6 @@ Rect Layer::getInputBounds() const { void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) { Rect tmpBounds = getInputBounds(); if (!tmpBounds.isValid()) { - info.setInputConfig(WindowInfo::InputConfig::TOUCH_MODAL, false); info.setInputConfig(WindowInfo::InputConfig::NOT_FOCUSABLE, true); info.touchableRegion.clear(); // A layer could have invalid input bounds and still expect to receive touch input if it has @@ -2307,7 +2306,6 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool disp mDrawingState.inputInfo.ownerUid = mOwnerUid; mDrawingState.inputInfo.ownerPid = mOwnerPid; mDrawingState.inputInfo.inputFeatures = WindowInfo::Feature::NO_INPUT_CHANNEL; - mDrawingState.inputInfo.setInputConfig(WindowInfo::InputConfig::TOUCH_MODAL, false); mDrawingState.inputInfo.displayId = getLayerStack().id; } -- cgit v1.2.3-59-g8ed1b From 66402271d3610ff9d0ed58432884521cd067d423 Mon Sep 17 00:00:00 2001 From: TeYuan Wang Date: Mon, 14 Feb 2022 10:25:00 +0800 Subject: Add systrace tag for thermal Bug: 218939123 Test: build Change-Id: I67912e91724e197132ae07e8ce55c60ec36b18a6 Ignore-AOSP-First: conflict in vendor/google_arc, need master first --- cmds/atrace/atrace.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index bb1d206f99..08a3d9a76e 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -246,7 +246,7 @@ static const TracingCategory k_categories[] = { { OPT, "events/gpu_mem/gpu_mem_total/enable" }, { OPT, "events/fastrpc/fastrpc_dma_stat/enable" }, } }, - { "thermal", "Thermal event", 0, { + { "thermal", "Thermal event", ATRACE_TAG_THERMAL, { { REQ, "events/thermal/thermal_temperature/enable" }, { OPT, "events/thermal/cdev_update/enable" }, } }, -- cgit v1.2.3-59-g8ed1b From 2739e839f88caa2bda1c072337bced240f103fc4 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 14 Feb 2022 17:42:00 -0800 Subject: SF: do not latch unsignaled in early offsets When we are in early offsets we are most likely in client composition and/or WM animating windows. Avoid latching unsignaled buffers in this case to avoid jank when an unsignaled buffers block newer transactions from getting applied in the next frame. Bug: 205153280 Test: modified TouchLatency app with long draws Change-Id: Ice5456db1dec1feaf11f6e022a1eaaedfb26781f --- .../surfaceflinger/Scheduler/VsyncModulator.cpp | 24 ++++++++++-- services/surfaceflinger/Scheduler/VsyncModulator.h | 5 +++ services/surfaceflinger/SurfaceFlinger.cpp | 23 ++++++++--- services/surfaceflinger/SurfaceFlinger.h | 4 +- .../tests/unittests/TestableSurfaceFlinger.h | 2 + .../tests/unittests/TransactionApplicationTest.cpp | 44 ++++++++++++++++++++++ 6 files changed, 90 insertions(+), 12 deletions(-) diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.cpp b/services/surfaceflinger/Scheduler/VsyncModulator.cpp index 245db0f5c7..be57b2acd7 100644 --- a/services/surfaceflinger/Scheduler/VsyncModulator.cpp +++ b/services/surfaceflinger/Scheduler/VsyncModulator.cpp @@ -134,16 +134,27 @@ VsyncModulator::VsyncConfig VsyncModulator::getVsyncConfig() const { return mVsyncConfig; } -const VsyncModulator::VsyncConfig& VsyncModulator::getNextVsyncConfig() const { +auto VsyncModulator::getNextVsyncConfigType() const -> VsyncConfigType { // Early offsets are used if we're in the middle of a refresh rate // change, or if we recently begin a transaction. if (!mEarlyWakeupRequests.empty() || mTransactionSchedule == Schedule::EarlyEnd || mEarlyTransactionFrames > 0 || mRefreshRateChangePending) { - return mVsyncConfigSet.early; + return VsyncConfigType::Early; } else if (mEarlyGpuFrames > 0) { - return mVsyncConfigSet.earlyGpu; + return VsyncConfigType::EarlyGpu; } else { - return mVsyncConfigSet.late; + return VsyncConfigType::Late; + } +} + +const VsyncModulator::VsyncConfig& VsyncModulator::getNextVsyncConfig() const { + switch (getNextVsyncConfigType()) { + case VsyncConfigType::Early: + return mVsyncConfigSet.early; + case VsyncConfigType::EarlyGpu: + return mVsyncConfigSet.earlyGpu; + case VsyncConfigType::Late: + return mVsyncConfigSet.late; } } @@ -176,4 +187,9 @@ void VsyncModulator::binderDied(const wp& who) { static_cast(updateVsyncConfigLocked()); } +bool VsyncModulator::isVsyncConfigDefault() const { + std::lock_guard lock(mMutex); + return getNextVsyncConfigType() == VsyncConfigType::Late; +} + } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.h b/services/surfaceflinger/Scheduler/VsyncModulator.h index 2000c546a0..537cae1d7c 100644 --- a/services/surfaceflinger/Scheduler/VsyncModulator.h +++ b/services/surfaceflinger/Scheduler/VsyncModulator.h @@ -109,11 +109,16 @@ public: [[nodiscard]] VsyncConfigOpt onDisplayRefresh(bool usedGpuComposition); + [[nodiscard]] bool isVsyncConfigDefault() const; + protected: // Called from unit tests as well void binderDied(const wp&) override EXCLUDES(mMutex); private: + enum class VsyncConfigType { Early, EarlyGpu, Late }; + + VsyncConfigType getNextVsyncConfigType() const REQUIRES(mMutex); const VsyncConfig& getNextVsyncConfig() const REQUIRES(mMutex); [[nodiscard]] VsyncConfig updateVsyncConfig() EXCLUDES(mMutex); [[nodiscard]] VsyncConfig updateVsyncConfigLocked() REQUIRES(mMutex); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5991b86d5d..80b7ce7b4d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3806,7 +3806,7 @@ bool SurfaceFlinger::frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) prediction->presentTime - expectedPresentTime >= earlyLatchVsyncThreshold; } bool SurfaceFlinger::shouldLatchUnsignaled(const sp& layer, const layer_state_t& state, - size_t numStates, size_t totalTXapplied) { + size_t numStates, size_t totalTXapplied) const { if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) { ALOGV("%s: false (LatchUnsignaledConfig::Disabled)", __func__); return false; @@ -3824,11 +3824,22 @@ bool SurfaceFlinger::shouldLatchUnsignaled(const sp& layer, const layer_s return false; } - if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer && - totalTXapplied > 0) { - ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; totalTXapplied=%zu)", __func__, - totalTXapplied); - return false; + if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer) { + if (totalTXapplied > 0) { + ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; totalTXapplied=%zu)", + __func__, totalTXapplied); + return false; + } + + // We don't want to latch unsignaled if are in early / client composition + // as it leads to jank due to RenderEngine waiting for unsignaled buffer + // or window animations being slow. + const auto isDefaultVsyncConfig = mVsyncModulator->isVsyncConfigDefault(); + if (!isDefaultVsyncConfig) { + ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; !isDefaultVsyncConfig)", + __func__); + return false; + } } if (!layer->simpleBufferUpdate(state)) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 02d5f1e49e..9674a77e6a 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -782,8 +782,8 @@ private: const std::unordered_set, SpHash>& bufferLayersReadyToPresent, size_t totalTXapplied) const REQUIRES(mStateLock); static LatchUnsignaledConfig getLatchUnsignaledConfig(); - static bool shouldLatchUnsignaled(const sp& layer, const layer_state_t&, - size_t numStates, size_t totalTXapplied); + bool shouldLatchUnsignaled(const sp& layer, const layer_state_t&, size_t numStates, + size_t totalTXapplied) const; bool stopTransactionProcessing(const std::unordered_set, SpHash>& applyTokensWithUnsignaledTransactions) const; bool applyTransactions(std::vector& transactions, int64_t vsyncId) diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 8cadb3175a..67e47e7b37 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -270,6 +270,8 @@ public: scheduler::TestableScheduler& mutableScheduler() { return *mScheduler; } scheduler::mock::SchedulerCallback& mockSchedulerCallback() { return mSchedulerCallback; } + auto& mutableVsyncModulator() { return mFlinger->mVsyncModulator; } + using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction; void setCreateBufferQueueFunction(CreateBufferQueueFunction f) { mFactory.mCreateBufferQueue = f; diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index 4683c5132f..eefa11f1aa 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -631,6 +631,28 @@ TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsTransactionInTheQueue) { kExpectedTransactionsApplied, kExpectedTransactionsPending); } +TEST_F(LatchUnsignaledAutoSingleLayerTest, DontLatchUnsignaledWhenEarlyOffset) { + const sp kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId = 1; + const auto kExpectedTransactionsApplied = 0u; + const auto kExpectedTransactionsPending = 1u; + + const auto unsignaledTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + }); + + // Get VsyncModulator out of the default config + static_cast(mFlinger.mutableVsyncModulator()->onRefreshRateChangeInitiated()); + + setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + class LatchUnsignaledDisabledTest : public LatchUnsignaledTest { public: void SetUp() override { @@ -999,4 +1021,26 @@ TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesUnsignaledFromTheQueue) { kExpectedTransactionsApplied, kExpectedTransactionsPending); } +TEST_F(LatchUnsignaledAlwaysTest, LatchUnsignaledWhenEarlyOffset) { + const sp kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId = 1; + const auto kExpectedTransactionsApplied = 1u; + const auto kExpectedTransactionsPending = 0u; + + const auto unsignaledTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + }); + + // Get VsyncModulator out of the default config + static_cast(mFlinger.mutableVsyncModulator()->onRefreshRateChangeInitiated()); + + setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + } // namespace android -- cgit v1.2.3-59-g8ed1b From 16f48f110c7a0e82c5962419d551b7aef7763914 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 14 Feb 2022 21:54:59 -0800 Subject: SF: add debug traces for latch unsignaled Bug: 205153280 Test: modified TouchLatency app with long draws Change-Id: If4c54dd5e1c968b4f1b7ff1b74c3fe1d35a0e0ea --- services/surfaceflinger/SurfaceFlinger.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 80b7ce7b4d..2e21225598 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3673,6 +3673,7 @@ bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { auto& [applyToken, transactionQueue] = *it; while (!transactionQueue.empty()) { if (stopTransactionProcessing(applyTokensWithUnsignaledTransactions)) { + ATRACE_NAME("stopTransactionProcessing"); break; } @@ -3684,6 +3685,7 @@ bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { transaction.originUid, transaction.states, bufferLayersReadyToPresent, transactions.size()); + ATRACE_INT("TransactionReadiness", static_cast(ready)); if (ready == TransactionReadiness::NotReady) { setTransactionFlags(eTransactionFlushNeeded); break; @@ -3721,6 +3723,7 @@ bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { const auto ready = [&]() REQUIRES(mStateLock) { if (pendingTransactions || stopTransactionProcessing(applyTokensWithUnsignaledTransactions)) { + ATRACE_NAME("pendingTransactions || stopTransactionProcessing"); return TransactionReadiness::NotReady; } @@ -3731,7 +3734,7 @@ bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { bufferLayersReadyToPresent, transactions.size()); }(); - + ATRACE_INT("TransactionReadiness", static_cast(ready)); if (ready == TransactionReadiness::NotReady) { mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction)); } else { @@ -3892,11 +3895,10 @@ auto SurfaceFlinger::transactionIsReadyToBeApplied( continue; } - ATRACE_NAME(layer->getName().c_str()); - const bool allowLatchUnsignaled = shouldLatchUnsignaled(layer, s, states.size(), totalTXapplied); - ATRACE_INT("allowLatchUnsignaled", allowLatchUnsignaled); + ATRACE_FORMAT("%s allowLatchUnsignaled=%s", layer->getName().c_str(), + allowLatchUnsignaled ? "true" : "false"); const bool acquireFenceChanged = s.bufferData && s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) && -- cgit v1.2.3-59-g8ed1b From 041415afbbac5223f614e7a5bd74b5a5e8723fff Mon Sep 17 00:00:00 2001 From: Chethan Kumar R E Date: Tue, 23 Nov 2021 17:42:22 +0530 Subject: Added surfaceflinger_layer_fuzzer Test: ./surfaceflinger_layer_fuzzer Bug: 189053744 Change-Id: I783b18389dd260b86eec2786c307d71d53785077 --- services/surfaceflinger/fuzzer/Android.bp | 16 ++ services/surfaceflinger/fuzzer/README.md | 23 +++ .../fuzzer/surfaceflinger_fuzzer.cpp | 29 --- .../fuzzer/surfaceflinger_fuzzers_utils.h | 29 +++ .../fuzzer/surfaceflinger_layer_fuzzer.cpp | 199 +++++++++++++++++++++ 5 files changed, 267 insertions(+), 29 deletions(-) create mode 100644 services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp diff --git a/services/surfaceflinger/fuzzer/Android.bp b/services/surfaceflinger/fuzzer/Android.bp index b0d216e5cd..1892e4c90e 100644 --- a/services/surfaceflinger/fuzzer/Android.bp +++ b/services/surfaceflinger/fuzzer/Android.bp @@ -102,3 +102,19 @@ cc_fuzz { "surfaceflinger_scheduler_fuzzer.cpp", ], } + +cc_fuzz { + name: "surfaceflinger_layer_fuzzer", + defaults: [ + "surfaceflinger_fuzz_defaults", + ], + header_libs: [ + "libgui_headers", + ], + static_libs: [ + "librenderengine", + ], + srcs: [ + "surfaceflinger_layer_fuzzer.cpp", + ], +} diff --git a/services/surfaceflinger/fuzzer/README.md b/services/surfaceflinger/fuzzer/README.md index 6231ca5536..78a7596ef3 100644 --- a/services/surfaceflinger/fuzzer/README.md +++ b/services/surfaceflinger/fuzzer/README.md @@ -3,6 +3,7 @@ + [SurfaceFlinger](#SurfaceFlinger) + [DisplayHardware](#DisplayHardware) + [Scheduler](#Scheduler) ++ [Layer](#Layer) # Fuzzer for SurfaceFlinger @@ -70,3 +71,25 @@ You can find the possible values in the fuzzer's source code. $ adb sync data $ adb shell /data/fuzz/arm64/surfaceflinger_scheduler_fuzzer/surfaceflinger_scheduler_fuzzer ``` + +# Fuzzer for Layer + +Layer supports the following parameters: +1. Display Connection Types (parameter name: `fakeDisplay`) +2. State Sets (parameter name: `traverseInZOrder`) +3. State Subsets (parameter name: `prepareCompositionState`) +4. Disconnect modes (parameter name: `disconnect`) +5. Data Spaces (parameter name: `setDataspace`) + +You can find the possible values in the fuzzer's source code. + +#### Steps to run +1. Build the fuzzer +``` + $ mm -j$(nproc) surfaceflinger_layer_fuzzer +``` +2. Run on device +``` + $ adb sync data + $ adb shell /data/fuzz/arm64/surfaceflinger_layer_fuzzer/surfaceflinger_layer_fuzzer +``` diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp index 30a6fbd416..afc1abdad7 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp @@ -29,35 +29,6 @@ static constexpr LatchUnsignaledConfig kLatchUnsignaledConfig[] = { LatchUnsignaledConfig::Disabled, }; -static constexpr ui::PixelFormat kPixelFormats[] = {ui::PixelFormat::RGBA_8888, - ui::PixelFormat::RGBX_8888, - ui::PixelFormat::RGB_888, - ui::PixelFormat::RGB_565, - ui::PixelFormat::BGRA_8888, - ui::PixelFormat::YCBCR_422_SP, - ui::PixelFormat::YCRCB_420_SP, - ui::PixelFormat::YCBCR_422_I, - ui::PixelFormat::RGBA_FP16, - ui::PixelFormat::RAW16, - ui::PixelFormat::BLOB, - ui::PixelFormat::IMPLEMENTATION_DEFINED, - ui::PixelFormat::YCBCR_420_888, - ui::PixelFormat::RAW_OPAQUE, - ui::PixelFormat::RAW10, - ui::PixelFormat::RAW12, - ui::PixelFormat::RGBA_1010102, - ui::PixelFormat::Y8, - ui::PixelFormat::Y16, - ui::PixelFormat::YV12, - ui::PixelFormat::DEPTH_16, - ui::PixelFormat::DEPTH_24, - ui::PixelFormat::DEPTH_24_STENCIL_8, - ui::PixelFormat::DEPTH_32F, - ui::PixelFormat::DEPTH_32F_STENCIL_8, - ui::PixelFormat::STENCIL_8, - ui::PixelFormat::YCBCR_P010, - ui::PixelFormat::HSV_888}; - static constexpr ui::Rotation kRotations[] = {ui::Rotation::Rotation0, ui::Rotation::Rotation90, ui::Rotation::Rotation180, ui::Rotation::Rotation270}; diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 0a458c2810..2fcf8564fe 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -123,6 +123,35 @@ static constexpr ui::ColorMode kColormodes[] = {ui::ColorMode::NATIVE, ui::ColorMode::BT2100_HLG, ui::ColorMode::DISPLAY_BT2020}; +static constexpr ui::PixelFormat kPixelFormats[] = {ui::PixelFormat::RGBA_8888, + ui::PixelFormat::RGBX_8888, + ui::PixelFormat::RGB_888, + ui::PixelFormat::RGB_565, + ui::PixelFormat::BGRA_8888, + ui::PixelFormat::YCBCR_422_SP, + ui::PixelFormat::YCRCB_420_SP, + ui::PixelFormat::YCBCR_422_I, + ui::PixelFormat::RGBA_FP16, + ui::PixelFormat::RAW16, + ui::PixelFormat::BLOB, + ui::PixelFormat::IMPLEMENTATION_DEFINED, + ui::PixelFormat::YCBCR_420_888, + ui::PixelFormat::RAW_OPAQUE, + ui::PixelFormat::RAW10, + ui::PixelFormat::RAW12, + ui::PixelFormat::RGBA_1010102, + ui::PixelFormat::Y8, + ui::PixelFormat::Y16, + ui::PixelFormat::YV12, + ui::PixelFormat::DEPTH_16, + ui::PixelFormat::DEPTH_24, + ui::PixelFormat::DEPTH_24_STENCIL_8, + ui::PixelFormat::DEPTH_32F, + ui::PixelFormat::DEPTH_32F_STENCIL_8, + ui::PixelFormat::STENCIL_8, + ui::PixelFormat::YCBCR_P010, + ui::PixelFormat::HSV_888}; + FloatRect getFuzzedFloatRect(FuzzedDataProvider *fdp) { return FloatRect(fdp->ConsumeFloatingPoint() /*left*/, fdp->ConsumeFloatingPoint() /*right*/, diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp new file mode 100644 index 0000000000..46d52dd221 --- /dev/null +++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp @@ -0,0 +1,199 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace android::fuzzer { +using namespace renderengine; + +constexpr uint16_t kRandomStringLength = 256; + +class LayerFuzzer { +public: + LayerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){}; + void init(); + void invokeBufferStateLayer(); + void invokeEffectLayer(); + LayerCreationArgs createLayerCreationArgs(TestableSurfaceFlinger* flinger, sp client); + Rect getFuzzedRect(); + FrameTimelineInfo getFuzzedFrameTimelineInfo(); + +private: + FuzzedDataProvider mFdp; +}; + +Rect LayerFuzzer::getFuzzedRect() { + return Rect(mFdp.ConsumeIntegral() /*left*/, mFdp.ConsumeIntegral() /*top*/, + mFdp.ConsumeIntegral() /*right*/, + mFdp.ConsumeIntegral() /*bottom*/); +} + +FrameTimelineInfo LayerFuzzer::getFuzzedFrameTimelineInfo() { + return FrameTimelineInfo{.vsyncId = mFdp.ConsumeIntegral(), + .inputEventId = mFdp.ConsumeIntegral()}; +} + +LayerCreationArgs LayerFuzzer::createLayerCreationArgs(TestableSurfaceFlinger* flinger, + sp client) { + flinger->setupScheduler(std::make_unique(), + std::make_unique(), + std::make_unique(), + std::make_unique()); + + return LayerCreationArgs(flinger->flinger(), client, + mFdp.ConsumeRandomLengthString(kRandomStringLength) /*name*/, + mFdp.ConsumeIntegral() /*flags*/, {} /*metadata*/); +} + +void LayerFuzzer::invokeEffectLayer() { + TestableSurfaceFlinger flinger; + sp client = sp::make(flinger.flinger()); + const LayerCreationArgs layerCreationArgs = createLayerCreationArgs(&flinger, client); + sp effectLayer = sp::make(layerCreationArgs); + + effectLayer->setColor({(mFdp.ConsumeFloatingPointInRange(0, 255) /*x*/, + mFdp.ConsumeFloatingPointInRange(0, 255) /*y*/, + mFdp.ConsumeFloatingPointInRange(0, 255) /*z*/)}); + effectLayer->setDataspace(mFdp.PickValueInArray(kDataspaces)); + sp parent = sp::make(layerCreationArgs); + effectLayer->setChildrenDrawingParent(parent); + + const FrameTimelineInfo frameInfo = getFuzzedFrameTimelineInfo(); + const int64_t postTime = mFdp.ConsumeIntegral(); + effectLayer->setFrameTimelineVsyncForBufferTransaction(frameInfo, postTime); + effectLayer->setFrameTimelineVsyncForBufferlessTransaction(frameInfo, postTime); + auto surfaceFrame = effectLayer->createSurfaceFrameForTransaction(frameInfo, postTime); + auto surfaceFrame1 = + effectLayer->createSurfaceFrameForBuffer(frameInfo, postTime, + mFdp.ConsumeRandomLengthString( + kRandomStringLength) /*bufferName*/); + effectLayer->addSurfaceFramePresentedForBuffer(surfaceFrame, + mFdp.ConsumeIntegral() /*acquireTime*/, + mFdp.ConsumeIntegral() /*currentTime*/); + effectLayer->addSurfaceFrameDroppedForBuffer(surfaceFrame1); + + parent.clear(); + client.clear(); + effectLayer.clear(); +} + +void LayerFuzzer::invokeBufferStateLayer() { + TestableSurfaceFlinger flinger; + sp client = sp::make(flinger.flinger()); + sp layer = + sp::make(createLayerCreationArgs(&flinger, client)); + sp fence = sp::make(); + const std::shared_ptr fenceTime = std::make_shared(fence); + + const CompositorTiming compositor = {mFdp.ConsumeIntegral(), + mFdp.ConsumeIntegral(), + mFdp.ConsumeIntegral()}; + std::packaged_task renderResult([&] { + return renderengine::RenderEngineResult{mFdp.ConsumeIntegral(), + base::unique_fd(fence->get())}; + }); + layer->onLayerDisplayed(renderResult.get_future()); + layer->releasePendingBuffer(mFdp.ConsumeIntegral()); + layer->finalizeFrameEventHistory(fenceTime, compositor); + layer->onPostComposition(nullptr, fenceTime, fenceTime, compositor); + layer->isBufferDue(mFdp.ConsumeIntegral()); + + layer->setTransform(mFdp.ConsumeIntegral()); + layer->setTransformToDisplayInverse(mFdp.ConsumeBool()); + layer->setCrop(getFuzzedRect()); + + layer->setHdrMetadata(getFuzzedHdrMetadata(&mFdp)); + layer->setDataspace(mFdp.PickValueInArray(kDataspaces)); + if (mFdp.ConsumeBool()) { + layer->setSurfaceDamageRegion(Region()); + layer->setTransparentRegionHint(Region()); + } else { + layer->setSurfaceDamageRegion(Region(getFuzzedRect())); + layer->setTransparentRegionHint(Region(getFuzzedRect())); + } + layer->setApi(mFdp.ConsumeIntegral()); + + native_handle_t* testHandle = native_handle_create(0, 1); + const bool ownsHandle = mFdp.ConsumeBool(); + sp nativeHandle = sp::make(testHandle, ownsHandle); + layer->setSidebandStream(nativeHandle); + layer->addFrameEvent(fence, mFdp.ConsumeIntegral() /*postedTime*/, + mFdp.ConsumeIntegral() /*requestedTime*/); + layer->computeSourceBounds(getFuzzedFloatRect(&mFdp)); + + layer->fenceHasSignaled(); + layer->framePresentTimeIsCurrent(mFdp.ConsumeIntegral()); + layer->onPreComposition(mFdp.ConsumeIntegral()); + const std::vector> callbacks; + layer->setTransactionCompletedListeners(callbacks); + + std::shared_ptr texture = std::make_shared< + renderengine::mock::FakeExternalTexture>(mFdp.ConsumeIntegral(), + mFdp.ConsumeIntegral(), + mFdp.ConsumeIntegral(), + static_cast( + mFdp.PickValueInArray(kPixelFormats)), + mFdp.ConsumeIntegral()); + layer->setBuffer(texture, {} /*bufferData*/, mFdp.ConsumeIntegral() /*postTime*/, + mFdp.ConsumeIntegral() /*desiredTime*/, + mFdp.ConsumeBool() /*isAutoTimestamp*/, + {mFdp.ConsumeIntegral()} /*dequeue*/, {} /*info*/); + + LayerRenderArea layerArea(*(flinger.flinger()), layer, getFuzzedRect(), + {mFdp.ConsumeIntegral(), + mFdp.ConsumeIntegral()} /*reqSize*/, + mFdp.PickValueInArray(kDataspaces), mFdp.ConsumeBool(), + getFuzzedRect(), mFdp.ConsumeBool()); + layerArea.render([]() {} /*drawLayers*/); + + if (!ownsHandle) { + native_handle_close(testHandle); + native_handle_delete(testHandle); + } + nativeHandle.clear(); + fence.clear(); + client.clear(); + layer.clear(); +} + +void LayerFuzzer::init() { + invokeBufferStateLayer(); + invokeEffectLayer(); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + LayerFuzzer layerFuzzer(data, size); + layerFuzzer.init(); + return 0; +} + +} // namespace android::fuzzer -- cgit v1.2.3-59-g8ed1b From 67362e316eec91896d49570f4af969fdb2b8322d Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 15 Feb 2022 11:03:55 -0800 Subject: SF: enable latch unsignaled for single layer by default Bug: 205153280 Test: modified TouchLatency app with long draws Change-Id: Ib9b156af1bcd901af7444ffbf2d937be83ea1368 --- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2e21225598..97a8eff257 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -505,7 +505,7 @@ LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() { return LatchUnsignaledConfig::Always; } - if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, false)) { + if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, true)) { return LatchUnsignaledConfig::AutoSingleLayer; } -- cgit v1.2.3-59-g8ed1b From 745dcaac220f57e925c38be345821f1917704b9b Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Wed, 26 Jan 2022 11:55:58 -0500 Subject: Pass display's colorTransform to RE even if HW handles it Even if the DPU handles the colorTransform, RE needs to know about it for A8 screen decorations layers. So pass the colorTransform to RE always. Add a new boolean, specifying whether the DPU handles it, so existing use cases can continue to ignore it. RE uses a color matrix to turn transparent pixels in the A8 screen decorations layer to black, providing antialiasing. If the DPU handles the colorTransform, that black will then be converted to another color (e.g. white, if the colorTransform comes from the "Color inversion" accesibility feature). So RE needs to convert it to a color that the DPU will then convert back to black, matching plastic next to the screen. Do this by inverting the upper left 3x3 of the matrix and applying it to black. If the color matrix is not invertible (note that the one used for "Color inversion" *is*), leave black unchanged. If the DPU does not handle the colorTransform, concat the A8 layer's color matrix with the colorTransform. Update libcompositionengine_test to use the proper colorTransform. Add GTEST_SKIP if R8 buffers are not supported (follow-up from I340de485fd62bea12a5a097f09073c4f7d58fa90). Bug: 215706351 Bug: 216178319 Test: librenderengine_test Test: libcompositionengine_test Test: manual Change-Id: Ib127620be4e5fc400ac2525c90dea1b9a29bd1f7 --- .../include/renderengine/DisplaySettings.h | 4 + libs/renderengine/skia/SkiaGLRenderEngine.cpp | 42 +++++-- libs/renderengine/tests/RenderEngineTest.cpp | 139 +++++++++++++++++++++ .../CompositionEngine/src/Output.cpp | 6 +- .../CompositionEngine/tests/OutputTest.cpp | 14 ++- 5 files changed, 190 insertions(+), 15 deletions(-) diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h index 2c51ccd334..40ba5ad2a8 100644 --- a/libs/renderengine/include/renderengine/DisplaySettings.h +++ b/libs/renderengine/include/renderengine/DisplaySettings.h @@ -54,6 +54,10 @@ struct DisplaySettings { // dataspace, in non-linear space. mat4 colorTransform = mat4(); + // If true, and colorTransform is non-identity, most client draw calls can + // ignore it. Some draws (e.g. screen decorations) may need it, though. + bool deviceHandlesColorTransform = false; + // An additional orientation flag to be applied after clipping the output. // By way of example, this may be used for supporting fullscreen screenshot // capture of a device in landscape while the buffer is in portrait diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index 763b82d043..b467b3538d 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -792,7 +792,7 @@ void SkiaGLRenderEngine::drawLayersInternal( // setup color filter if necessary sk_sp displayColorTransform; - if (display.colorTransform != mat4()) { + if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) { displayColorTransform = SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform)); } const bool ctModifiesAlpha = @@ -1107,11 +1107,37 @@ void SkiaGLRenderEngine::drawLayersInternal( if (imageTextureRef->colorType() == kAlpha_8_SkColorType) { LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with A8"); - float matrix[] = { 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0, 0, 0, -1, 1 }; - paint.setColorFilter(SkColorFilters::Matrix(matrix)); + + // SysUI creates the alpha layer as a coverage layer, which is + // appropriate for the DPU. Use a color matrix to convert it to + // a mask. + // TODO (b/219525258): Handle input as a mask. + // + // The color matrix will convert A8 pixels with no alpha to + // black, as described by this vector. If the display handles + // the color transform, we need to invert it to find the color + // that will result in black after the DPU applies the transform. + SkV4 black{0.0f, 0.0f, 0.0f, 1.0f}; // r, g, b, a + if (display.colorTransform != mat4() && display.deviceHandlesColorTransform) { + SkM44 colorSpaceMatrix = getSkM44(display.colorTransform); + if (colorSpaceMatrix.invert(&colorSpaceMatrix)) { + black = colorSpaceMatrix * black; + } else { + // We'll just have to use 0,0,0 as black, which should + // be close to correct. + ALOGI("Could not invert colorTransform!"); + } + } + SkColorMatrix colorMatrix(0, 0, 0, 0, black[0], + 0, 0, 0, 0, black[1], + 0, 0, 0, 0, black[2], + 0, 0, 0, -1, 1); + if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) { + // On the other hand, if the device doesn't handle it, we + // have to apply it ourselves. + colorMatrix.postConcat(toSkColorMatrix(display.colorTransform)); + } + paint.setColorFilter(SkColorFilters::Matrix(colorMatrix)); } } else { ATRACE_NAME("DrawColor"); @@ -1134,8 +1160,8 @@ void SkiaGLRenderEngine::drawLayersInternal( paint.setBlendMode(SkBlendMode::kSrc); } - // A color filter will have been set for an A8 buffer. Do not replace - // it with the displayColorTransform, which shouldn't affect A8. + // An A8 buffer will already have the proper color filter attached to + // its paint, including the displayColorTransform as needed. if (!paint.getColorFilter()) { paint.setColorFilter(displayColorTransform); } diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index e197150afe..add7a940de 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -2627,6 +2627,7 @@ TEST_P(RenderEngineTest, r8_behaves_as_mask) { const auto r8Buffer = allocateR8Buffer(2, 1); if (!r8Buffer) { + GTEST_SKIP() << "Test is only necessary on devices that support r8"; return; } { @@ -2677,6 +2678,144 @@ TEST_P(RenderEngineTest, r8_behaves_as_mask) { expectBufferColor(Rect(0, 0, 1, 1), 0, 0, 0, 255); expectBufferColor(Rect(1, 0, 2, 1), 0, 255, 0, 255); } + +TEST_P(RenderEngineTest, r8_respects_color_transform) { + if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) { + return; + } + + initializeRenderEngine(); + + const auto r8Buffer = allocateR8Buffer(2, 1); + if (!r8Buffer) { + GTEST_SKIP() << "Test is only necessary on devices that support r8"; + return; + } + { + uint8_t* pixels; + r8Buffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); + pixels[0] = 0; + pixels[1] = 255; + r8Buffer->getBuffer()->unlock(); + } + + const auto rect = Rect(0, 0, 2, 1); + const renderengine::DisplaySettings display{ + .physicalDisplay = rect, + .clip = rect, + .outputDataspace = ui::Dataspace::SRGB, + // Verify that the R8 layer respects the color transform when + // deviceHandlesColorTransform is false. This transform converts + // pure red to pure green. That will occur when the R8 buffer is + // 255. When the R8 buffer is 0, it will still change to black, as + // with r8_behaves_as_mask. + .colorTransform = mat4(0, 1, 0, 0, + 0, 0, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1), + .deviceHandlesColorTransform = false, + }; + + const auto redBuffer = allocateAndFillSourceBuffer(2, 1, ubyte4(255, 0, 0, 255)); + const renderengine::LayerSettings redLayer{ + .geometry.boundaries = rect.toFloatRect(), + .source = + renderengine::PixelSource{ + .buffer = + renderengine::Buffer{ + .buffer = redBuffer, + }, + }, + .alpha = 1.0f, + }; + const renderengine::LayerSettings r8Layer{ + .geometry.boundaries = rect.toFloatRect(), + .source = + renderengine::PixelSource{ + .buffer = + renderengine::Buffer{ + .buffer = r8Buffer, + }, + }, + .alpha = 1.0f, + }; + + std::vector layers{redLayer, r8Layer}; + invokeDraw(display, layers); + + expectBufferColor(Rect(0, 0, 1, 1), 0, 0, 0, 255); + expectBufferColor(Rect(1, 0, 2, 1), 0, 255, 0, 255); +} + +TEST_P(RenderEngineTest, r8_respects_color_transform_when_device_handles) { + if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) { + return; + } + + initializeRenderEngine(); + + const auto r8Buffer = allocateR8Buffer(2, 1); + if (!r8Buffer) { + GTEST_SKIP() << "Test is only necessary on devices that support r8"; + return; + } + { + uint8_t* pixels; + r8Buffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); + pixels[0] = 0; + pixels[1] = 255; + r8Buffer->getBuffer()->unlock(); + } + + const auto rect = Rect(0, 0, 2, 1); + const renderengine::DisplaySettings display{ + .physicalDisplay = rect, + .clip = rect, + .outputDataspace = ui::Dataspace::SRGB, + // If deviceHandlesColorTransform is true, pixels where the A8 + // buffer is opaque are unaffected. If the colorTransform is + // invertible, pixels where the A8 buffer are transparent have the + // inverse applied to them so that the DPU will convert them back to + // black. Test with an arbitrary, invertible matrix. + .colorTransform = mat4(1, 0, 0, 2, + 3, 1, 2, 5, + 0, 5, 3, 0, + 0, 1, 0, 2), + .deviceHandlesColorTransform = true, + }; + + const auto redBuffer = allocateAndFillSourceBuffer(2, 1, ubyte4(255, 0, 0, 255)); + const renderengine::LayerSettings redLayer{ + .geometry.boundaries = rect.toFloatRect(), + .source = + renderengine::PixelSource{ + .buffer = + renderengine::Buffer{ + .buffer = redBuffer, + }, + }, + .alpha = 1.0f, + }; + const renderengine::LayerSettings r8Layer{ + .geometry.boundaries = rect.toFloatRect(), + .source = + renderengine::PixelSource{ + .buffer = + renderengine::Buffer{ + .buffer = r8Buffer, + }, + }, + .alpha = 1.0f, + }; + + std::vector layers{redLayer, r8Layer}; + invokeDraw(display, layers); + + expectBufferColor(Rect(1, 0, 2, 1), 255, 0, 0, 255); // Still red. + expectBufferColor(Rect(0, 0, 1, 1), 0, 70, 0, 255); +} } // namespace renderengine } // namespace android diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 65f9731afe..e0362521eb 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -1079,9 +1079,9 @@ std::optional Output::composeSurfaces( clientCompositionDisplay.targetLuminanceNits = outputState.clientTargetWhitePointNits; // Compute the global color transform matrix. - if (!outputState.usesDeviceComposition && !getSkipColorTransform()) { - clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix; - } + clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix; + clientCompositionDisplay.deviceHandlesColorTransform = + outputState.usesDeviceComposition || getSkipColorTransform(); // Generate the client composition requests for the layers on this output. std::vector clientCompositionLayersFE; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index e72bc9f66d..cab4b8de56 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -3487,7 +3487,8 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrMixedComposi .maxLuminance = kDefaultMaxLuminance, .currentLuminanceNits = kDefaultMaxLuminance, .outputDataspace = kDefaultOutputDataspace, - .colorTransform = mat4(), + .colorTransform = kDefaultColorTransformMat, + .deviceHandlesColorTransform = true, .orientation = kDefaultOutputOrientationFlags, .targetLuminanceNits = kClientTargetLuminanceNits}) .execute() @@ -3505,7 +3506,8 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, .maxLuminance = kDefaultMaxLuminance, .currentLuminanceNits = kDisplayLuminance, .outputDataspace = kDefaultOutputDataspace, - .colorTransform = mat4(), + .colorTransform = kDefaultColorTransformMat, + .deviceHandlesColorTransform = true, .orientation = kDefaultOutputOrientationFlags, .targetLuminanceNits = kClientTargetLuminanceNits}) .execute() @@ -3522,7 +3524,8 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrMixedComp .maxLuminance = kDefaultMaxLuminance, .currentLuminanceNits = kDefaultMaxLuminance, .outputDataspace = kDefaultOutputDataspace, - .colorTransform = mat4(), + .colorTransform = kDefaultColorTransformMat, + .deviceHandlesColorTransform = true, .orientation = kDefaultOutputOrientationFlags, .targetLuminanceNits = kClientTargetLuminanceNits}) .execute() @@ -3540,6 +3543,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrOnlyClientCo .currentLuminanceNits = kDefaultMaxLuminance, .outputDataspace = kDefaultOutputDataspace, .colorTransform = kDefaultColorTransformMat, + .deviceHandlesColorTransform = false, .orientation = kDefaultOutputOrientationFlags, .targetLuminanceNits = kClientTargetLuminanceNits}) .execute() @@ -3557,6 +3561,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrOnlyClien .currentLuminanceNits = kDefaultMaxLuminance, .outputDataspace = kDefaultOutputDataspace, .colorTransform = kDefaultColorTransformMat, + .deviceHandlesColorTransform = false, .orientation = kDefaultOutputOrientationFlags, .targetLuminanceNits = kClientTargetLuminanceNits}) .execute() @@ -3574,7 +3579,8 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, .maxLuminance = kDefaultMaxLuminance, .currentLuminanceNits = kDefaultMaxLuminance, .outputDataspace = kDefaultOutputDataspace, - .colorTransform = mat4(), + .colorTransform = kDefaultColorTransformMat, + .deviceHandlesColorTransform = true, .orientation = kDefaultOutputOrientationFlags, .targetLuminanceNits = kClientTargetLuminanceNits}) .execute() -- cgit v1.2.3-59-g8ed1b From e43ff72e409ddefeec0edeb4c514febce9faff3e Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 15 Feb 2022 14:44:25 -0800 Subject: SF: treat prediction expired as app missed deadline We are keeping enough vsyncIds for a reasonable app to send back their vsyncId. If we can't find the vsync id of that app, we can be pretty confident that the app had a huge schedule delay. Bug: 211763914 Test: SF unit tests Change-Id: I046a87e566844bb140df75df3d06f809b7d99155 --- services/surfaceflinger/FrameTimeline/FrameTimeline.cpp | 15 ++++++++++----- .../surfaceflinger/tests/unittests/FrameTimelineTest.cpp | 4 ++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 86e96d769c..81747d596a 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -492,17 +492,22 @@ std::string SurfaceFrame::miniDump() const { void SurfaceFrame::classifyJankLocked(int32_t displayFrameJankType, const Fps& refreshRate, nsecs_t& deadlineDelta) { - if (mPredictionState == PredictionState::Expired || - mActuals.presentTime == Fence::SIGNAL_TIME_INVALID) { + if (mActuals.presentTime == Fence::SIGNAL_TIME_INVALID) { // Cannot do any classification for invalid present time. - // For prediction expired case, we do not know what happened here to classify this - // correctly. This could potentially be AppDeadlineMissed but that's assuming no app will - // request frames 120ms apart. mJankType = JankType::Unknown; deadlineDelta = -1; return; } + if (mPredictionState == PredictionState::Expired) { + // We classify prediction expired as AppDeadlineMissed as the + // TokenManager::kMaxTokens we store is large enough to account for a + // reasonable app, so prediction expire would mean a huge scheduling delay. + mJankType = JankType::AppDeadlineMissed; + deadlineDelta = -1; + return; + } + if (mPredictionState == PredictionState::None) { // Cannot do jank classification on frames that don't have a token. return; diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp index 397c6193bf..834a560b3b 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -1279,7 +1279,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { validateTraceEvent(actualSurfaceFrameEnd2, protoPresentedSurfaceFrameActualEnd); } -TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDoesNotTraceExpectedTimeline) { +TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredIsAppMissedDeadline) { auto tracingSession = getTracingSessionForTest(); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -1312,7 +1312,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDoesNotTraceExpecte createProtoActualSurfaceFrameStart(traceCookie + 1, surfaceFrameToken, displayFrameToken, sPidOne, sLayerNameOne, FrameTimelineEvent::PRESENT_UNSPECIFIED, false, - false, FrameTimelineEvent::JANK_UNKNOWN, + false, FrameTimelineEvent::JANK_APP_DEADLINE_MISSED, FrameTimelineEvent::PREDICTION_EXPIRED, true); auto protoActualSurfaceFrameEnd = createProtoFrameEnd(traceCookie + 1); -- cgit v1.2.3-59-g8ed1b From 9f410f0adfb4f44fa149cbc7589b13ea88007157 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Sat, 8 Jan 2022 16:22:46 -0800 Subject: SF: Avoid allocation on hot path to IF The number of layer stacks and listeners is small, and the predominant operations are lookup and iteration respectively, so store them on the stack contiguously to avoid hashing/allocation/indirection. Preallocate the WindowInfo and DisplayInfo vectors, since reallocating the former involves copying strings and fiddling with sp<> ref counts. Bug: 185536303 Test: simpleperf Test: WindowInfosListenerTest Change-Id: I5d1d1fc3b2639a4ee5056697e1a3581c11174173 --- services/surfaceflinger/DisplayDevice.cpp | 9 ++- services/surfaceflinger/DisplayDevice.h | 11 +++- services/surfaceflinger/SurfaceFlinger.cpp | 65 +++++++++------------- .../surfaceflinger/WindowInfosListenerInvoker.cpp | 23 ++++---- .../surfaceflinger/WindowInfosListenerInvoker.h | 11 ++-- 5 files changed, 58 insertions(+), 61 deletions(-) diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index f542161b93..eef00522dc 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -141,7 +141,7 @@ uint32_t DisplayDevice::getPageFlipCount() const { return mCompositionDisplay->getRenderSurface()->getPageFlipCount(); } -std::pair DisplayDevice::getInputInfo() const { +auto DisplayDevice::getInputInfo() const -> InputInfo { gui::DisplayInfo info; info.displayId = getLayerStack().id; @@ -166,10 +166,13 @@ std::pair DisplayDevice::getInputInfo() const { info.logicalWidth = getLayerStackSpaceRect().width(); info.logicalHeight = getLayerStackSpaceRect().height(); - return {info, displayTransform}; + + return {.info = info, + .transform = displayTransform, + .receivesInput = receivesInput(), + .isSecure = isSecure()}; } -// ---------------------------------------------------------------------------- void DisplayDevice::setPowerMode(hal::PowerMode mode) { mPowerMode = mode; getCompositionDisplay()->setCompositionEnabled(mPowerMode != hal::PowerMode::OFF); diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 3cae30fe92..bf6b31a76b 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -174,9 +174,14 @@ public: return mDeviceProductInfo; } - // Get the DisplayInfo that will be sent to InputFlinger, and the display transform that should - // be applied to all the input windows on the display. - std::pair getInputInfo() const; + struct InputInfo { + gui::DisplayInfo info; + ui::Transform transform; + bool receivesInput; + bool isSecure; + }; + + InputInfo getInputInfo() const; /* ------------------------------------------------------------------------ * Display power mode management. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9716d8ecea..344c2cc7d4 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -3258,60 +3259,48 @@ void SurfaceFlinger::persistDisplayBrightness(bool needsComposite) { void SurfaceFlinger::buildWindowInfos(std::vector& outWindowInfos, std::vector& outDisplayInfos) { - struct Details { - Details(bool receivesInput, bool isSecure, const ui::Transform& transform, - const DisplayInfo& info) - : receivesInput(receivesInput), - isSecure(isSecure), - transform(std::move(transform)), - info(std::move(info)) {} - bool receivesInput; - bool isSecure; - ui::Transform transform; - DisplayInfo info; - }; - std::unordered_map inputDisplayDetails; + ftl::SmallMap displayInputInfos; + for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { - const uint32_t layerStackId = display->getLayerStack().id; - const auto& [info, transform] = display->getInputInfo(); - const auto& [it, emplaced] = - inputDisplayDetails.try_emplace(layerStackId, display->receivesInput(), - display->isSecure(), transform, info); + const auto layerStack = display->getLayerStack(); + const auto info = display->getInputInfo(); + + const auto [it, emplaced] = displayInputInfos.try_emplace(layerStack, info); if (emplaced) { continue; } - // There is more than one display for the layerStack. In this case, the first display that - // is configured to receive input takes precedence. - auto& details = it->second; - if (details.receivesInput) { + // If the layer stack is mirrored on multiple displays, the first display that is configured + // to receive input takes precedence. + auto& otherInfo = it->second; + if (otherInfo.receivesInput) { ALOGW_IF(display->receivesInput(), "Multiple displays claim to accept input for the same layer stack: %u", - layerStackId); - continue; + layerStack.id); + } else { + otherInfo = info; } - details.receivesInput = display->receivesInput(); - details.isSecure = display->isSecure(); - details.transform = std::move(transform); - details.info = std::move(info); } + static size_t sNumWindowInfos = 0; + outWindowInfos.reserve(sNumWindowInfos); + sNumWindowInfos = 0; + mDrawingState.traverseInReverseZOrder([&](Layer* layer) { if (!layer->needsInputInfo()) return; - const uint32_t layerStackId = layer->getLayerStack().id; - const auto it = inputDisplayDetails.find(layerStackId); - if (it == inputDisplayDetails.end()) { - // Do not create WindowInfos for windows on displays that cannot receive input. - return; + // Do not create WindowInfos for windows on displays that cannot receive input. + if (const auto opt = displayInputInfos.get(layer->getLayerStack())) { + const auto& info = opt->get(); + outWindowInfos.push_back(layer->fillInputInfo(info.transform, info.isSecure)); } - - const auto& details = it->second; - outWindowInfos.push_back(layer->fillInputInfo(details.transform, details.isSecure)); }); - for (const auto& [_, details] : inputDisplayDetails) { - outDisplayInfos.push_back(std::move(details.info)); + sNumWindowInfos = outWindowInfos.size(); + + outDisplayInfos.reserve(displayInputInfos.size()); + for (const auto& [_, info] : displayInputInfos) { + outDisplayInfos.push_back(info.info); } } diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp index 23cd99336a..30b9d8f1cb 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp +++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp @@ -14,10 +14,11 @@ * limitations under the License. */ -#include "WindowInfosListenerInvoker.h" +#include #include -#include + #include "SurfaceFlinger.h" +#include "WindowInfosListenerInvoker.h" namespace android { @@ -41,18 +42,17 @@ WindowInfosListenerInvoker::WindowInfosListenerInvoker(SurfaceFlinger& flinger) : mFlinger(flinger), mWindowInfosReportedListener(sp::make(*this)) {} -void WindowInfosListenerInvoker::addWindowInfosListener( - const sp& windowInfosListener) { - sp asBinder = IInterface::asBinder(windowInfosListener); - +void WindowInfosListenerInvoker::addWindowInfosListener(sp listener) { + sp asBinder = IInterface::asBinder(listener); asBinder->linkToDeath(this); + std::scoped_lock lock(mListenersMutex); - mWindowInfosListeners.emplace(asBinder, windowInfosListener); + mWindowInfosListeners.try_emplace(asBinder, std::move(listener)); } void WindowInfosListenerInvoker::removeWindowInfosListener( - const sp& windowInfosListener) { - sp asBinder = IInterface::asBinder(windowInfosListener); + const sp& listener) { + sp asBinder = IInterface::asBinder(listener); std::scoped_lock lock(mListenersMutex); asBinder->unlinkToDeath(this); @@ -67,12 +67,11 @@ void WindowInfosListenerInvoker::binderDied(const wp& who) { void WindowInfosListenerInvoker::windowInfosChanged(const std::vector& windowInfos, const std::vector& displayInfos, bool shouldSync) { - std::unordered_set, SpHash> windowInfosListeners; - + ftl::SmallVector, kStaticCapacity> windowInfosListeners; { std::scoped_lock lock(mListenersMutex); for (const auto& [_, listener] : mWindowInfosListeners) { - windowInfosListeners.insert(listener); + windowInfosListeners.push_back(listener); } } diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h index 2eabf481c8..d8d8d0f570 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.h +++ b/services/surfaceflinger/WindowInfosListenerInvoker.h @@ -20,10 +20,8 @@ #include #include #include +#include #include -#include - -#include "WpHash.h" namespace android { @@ -33,7 +31,7 @@ class WindowInfosListenerInvoker : public IBinder::DeathRecipient { public: explicit WindowInfosListenerInvoker(SurfaceFlinger&); - void addWindowInfosListener(const sp& windowInfosListener); + void addWindowInfosListener(sp); void removeWindowInfosListener(const sp& windowInfosListener); void windowInfosChanged(const std::vector&, @@ -48,8 +46,11 @@ private: SurfaceFlinger& mFlinger; std::mutex mListenersMutex; - std::unordered_map, const sp, WpHash> + + static constexpr size_t kStaticCapacity = 3; + ftl::SmallMap, const sp, kStaticCapacity> mWindowInfosListeners GUARDED_BY(mListenersMutex); + sp mWindowInfosReportedListener; std::atomic mCallbacksPending{0}; }; -- cgit v1.2.3-59-g8ed1b From bc6c8601faa2367ac9177fdd5ac498a3922ddb29 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Tue, 11 Jan 2022 08:53:24 -0800 Subject: SF: Make thread safety macros zero-cost ON_MAIN_THREAD(mDisplays) incurred a copy. In other words, this failed: decltype(auto) displays = ON_MAIN_THREAD(mDisplays); static_assert(std::is_lvalue_reference_v); Bug: 182939859 Test: static_assert Test: simpleperf Change-Id: I19900d0350b832cd71457e5a6f11fa65b16e0412 --- services/surfaceflinger/SurfaceFlinger.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 344c2cc7d4..59c07b6db1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -147,15 +147,16 @@ #define MAIN_THREAD ACQUIRE(mStateLock) RELEASE(mStateLock) +// Note: The parentheses around `expr` are needed to deduce an lvalue or rvalue reference. #define ON_MAIN_THREAD(expr) \ - [&] { \ + [&]() -> decltype(auto) { \ LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \ UnnecessaryLock lock(mStateLock); \ return (expr); \ }() #define MAIN_THREAD_GUARD(expr) \ - [&] { \ + [&]() -> decltype(auto) { \ LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \ MainThreadScopedGuard lock(SF_MAIN_THREAD); \ return (expr); \ @@ -1345,9 +1346,8 @@ void SurfaceFlinger::disableExpensiveRendering() { auto future = mScheduler->schedule([=]() MAIN_THREAD { ATRACE_CALL(); if (mPowerAdvisor.isUsingExpensiveRendering()) { - const auto& displays = ON_MAIN_THREAD(mDisplays); - for (const auto& [_, display] : displays) { - const static constexpr auto kDisable = false; + for (const auto& [_, display] : mDisplays) { + constexpr bool kDisable = false; mPowerAdvisor.setExpensiveRenderingExpected(display->getId(), kDisable); } } @@ -3236,9 +3236,7 @@ void SurfaceFlinger::persistDisplayBrightness(bool needsComposite) { return; } - const auto& displays = ON_MAIN_THREAD(mDisplays); - - for (const auto& [_, display] : displays) { + for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { if (const auto brightness = display->getStagedBrightness(); brightness) { if (!needsComposite) { const status_t error = -- cgit v1.2.3-59-g8ed1b From 17f6b97257ef79f6252a5a45ac3a1e647b3a5fd0 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Tue, 25 Jan 2022 13:41:52 -0800 Subject: FTL: Prevent InitializerList overflow Users so far use the deduction guide, but this should not compile: ftl::StaticVector vector = ftl::init::list(0)(1); Bug: 185536303 Test: m ftl_test Change-Id: Icc1263ebdb9326948f0fc2f9c9f01f21b0b8302d --- include/ftl/static_vector.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/ftl/static_vector.h b/include/ftl/static_vector.h index b7f8c29dec..70f1721d4a 100644 --- a/include/ftl/static_vector.h +++ b/include/ftl/static_vector.h @@ -178,7 +178,9 @@ class StaticVector final : details::ArrayTraits, template StaticVector(InitializerList, Types...>&& list) : StaticVector(std::index_sequence<0, 0, Size>{}, std::make_index_sequence{}, - std::index_sequence{}, list.tuple) {} + std::index_sequence{}, list.tuple) { + static_assert(sizeof...(Sizes) < N, "Too many elements"); + } ~StaticVector() { std::destroy(begin(), end()); } -- cgit v1.2.3-59-g8ed1b From 953b7fd033714607ac14e106102835ecf03e3dc5 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Sat, 8 Jan 2022 19:34:59 -0800 Subject: SF: Pull FpsRange to scheduler/Fps.h Bug: 185535769 Test: libsurfaceflinger_unittest Change-Id: Iec0696d752e7cd071f68a9c15be5f28e3b7f5c07 --- .../Scheduler/RefreshRateConfigs.cpp | 32 +++++++++------------- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 28 ++++--------------- .../Scheduler/include/scheduler/Fps.h | 26 ++++++++++++++++++ .../surfaceflinger/tests/unittests/FpsTest.cpp | 10 +++++++ .../tests/unittests/RefreshRateConfigsTest.cpp | 11 -------- 5 files changed, 55 insertions(+), 52 deletions(-) diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 3b9cfa6340..eeeaac1170 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -69,11 +69,6 @@ std::vector constructKnownFrameRates(const DisplayModes& modes) { using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType; using RefreshRate = RefreshRateConfigs::RefreshRate; -bool RefreshRate::inPolicy(Fps minRefreshRate, Fps maxRefreshRate) const { - using fps_approx_ops::operator<=; - return minRefreshRate <= getFps() && getFps() <= maxRefreshRate; -} - std::string RefreshRate::toString() const { return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}", getModeId().value(), mode->getHwcId(), getFps().getValue(), @@ -84,7 +79,7 @@ std::string RefreshRateConfigs::Policy::toString() const { return base::StringPrintf("default mode ID: %d, allowGroupSwitching = %d" ", primary range: %s, app request range: %s", defaultMode.value(), allowGroupSwitching, - primaryRange.toString().c_str(), appRequestRange.toString().c_str()); + to_string(primaryRange).c_str(), to_string(appRequestRange).c_str()); } std::pair RefreshRateConfigs::getDisplayFrames(nsecs_t layerPeriod, @@ -396,8 +391,9 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vectorinPolicy(policy->primaryRange.min, - policy->primaryRange.max); + const bool inPrimaryRange = + policy->primaryRange.includes(scores[i].refreshRate->getFps()); + if ((primaryRangeIsSingleRate || !inPrimaryRange) && !(layer.focused && (layer.vote == LayerVoteType::ExplicitDefault || @@ -746,7 +742,7 @@ bool RefreshRateConfigs::isPolicyValidLocked(const Policy& policy) const { return false; } const RefreshRate& refreshRate = *iter->second; - if (!refreshRate.inPolicy(policy.primaryRange.min, policy.primaryRange.max)) { + if (!policy.primaryRange.includes(refreshRate.getFps())) { ALOGE("Default mode is not in the primary range."); return false; } @@ -843,7 +839,7 @@ void RefreshRateConfigs::constructAvailableRefreshRates() { ALOGV("constructAvailableRefreshRates: %s ", policy->toString().c_str()); auto filterRefreshRates = - [&](Fps min, Fps max, const char* listName, + [&](FpsRange range, const char* rangeName, std::vector* outRefreshRates) REQUIRES(mLock) { getSortedRefreshRateListLocked( [&](const RefreshRate& refreshRate) REQUIRES(mLock) { @@ -855,13 +851,13 @@ void RefreshRateConfigs::constructAvailableRefreshRates() { mode->getDpiY() == defaultMode->getDpiY() && (policy->allowGroupSwitching || mode->getGroup() == defaultMode->getGroup()) && - refreshRate.inPolicy(min, max); + range.includes(mode->getFps()); }, outRefreshRates); - LOG_ALWAYS_FATAL_IF(outRefreshRates->empty(), - "No matching modes for %s range: min=%s max=%s", listName, - to_string(min).c_str(), to_string(max).c_str()); + LOG_ALWAYS_FATAL_IF(outRefreshRates->empty(), "No matching modes for %s range %s", + rangeName, to_string(range).c_str()); + auto stringifyRefreshRates = [&]() -> std::string { std::string str; for (auto refreshRate : *outRefreshRates) { @@ -869,13 +865,11 @@ void RefreshRateConfigs::constructAvailableRefreshRates() { } return str; }; - ALOGV("%s refresh rates: %s", listName, stringifyRefreshRates().c_str()); + ALOGV("%s refresh rates: %s", rangeName, stringifyRefreshRates().c_str()); }; - filterRefreshRates(policy->primaryRange.min, policy->primaryRange.max, "primary", - &mPrimaryRefreshRates); - filterRefreshRates(policy->appRequestRange.min, policy->appRequestRange.max, "app request", - &mAppRequestRefreshRates); + filterRefreshRates(policy->primaryRange, "primary", &mPrimaryRefreshRates); + filterRefreshRates(policy->appRequestRange, "app request", &mAppRequestRefreshRates); } Fps RefreshRateConfigs::findClosestKnownFrameRate(Fps frameRate) const { diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index ade1787c97..f5b97c27c6 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -22,7 +22,6 @@ #include #include -#include #include #include @@ -101,21 +100,6 @@ public: using AllRefreshRatesMapType = std::unordered_map>; - struct FpsRange { - Fps min = Fps::fromValue(0.f); - Fps max = Fps::fromValue(std::numeric_limits::max()); - - bool operator==(const FpsRange& other) const { - return isApproxEqual(min, other.min) && isApproxEqual(max, other.max); - } - - bool operator!=(const FpsRange& other) const { return !(*this == other); } - - std::string toString() const { - return base::StringPrintf("[%s %s]", to_string(min).c_str(), to_string(max).c_str()); - } - }; - struct Policy { private: static constexpr int kAllowGroupSwitchingDefault = false; @@ -140,24 +124,24 @@ public: Policy() = default; - Policy(DisplayModeId defaultMode, const FpsRange& range) + Policy(DisplayModeId defaultMode, FpsRange range) : Policy(defaultMode, kAllowGroupSwitchingDefault, range, range) {} - Policy(DisplayModeId defaultMode, bool allowGroupSwitching, const FpsRange& range) + Policy(DisplayModeId defaultMode, bool allowGroupSwitching, FpsRange range) : Policy(defaultMode, allowGroupSwitching, range, range) {} - Policy(DisplayModeId defaultMode, const FpsRange& primaryRange, - const FpsRange& appRequestRange) + Policy(DisplayModeId defaultMode, FpsRange primaryRange, FpsRange appRequestRange) : Policy(defaultMode, kAllowGroupSwitchingDefault, primaryRange, appRequestRange) {} - Policy(DisplayModeId defaultMode, bool allowGroupSwitching, const FpsRange& primaryRange, - const FpsRange& appRequestRange) + Policy(DisplayModeId defaultMode, bool allowGroupSwitching, FpsRange primaryRange, + FpsRange appRequestRange) : defaultMode(defaultMode), allowGroupSwitching(allowGroupSwitching), primaryRange(primaryRange), appRequestRange(appRequestRange) {} bool operator==(const Policy& other) const { + using namespace fps_approx_ops; return defaultMode == other.defaultMode && primaryRange == other.primaryRange && appRequestRange == other.appRequestRange && allowGroupSwitching == other.allowGroupSwitching; diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Fps.h b/services/surfaceflinger/Scheduler/include/scheduler/Fps.h index 639b3e5ed8..bd4f40989d 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/Fps.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/Fps.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include #include @@ -60,6 +61,13 @@ private: nsecs_t mPeriod = 0; }; +struct FpsRange { + Fps min = Fps::fromValue(0.f); + Fps max = Fps::fromValue(std::numeric_limits::max()); + + bool includes(Fps) const; +}; + static_assert(std::is_trivially_copyable_v); constexpr Fps operator""_Hz(unsigned long long frequency) { @@ -111,8 +119,21 @@ inline bool operator>=(Fps lhs, Fps rhs) { return !isApproxLess(lhs, rhs); } +inline bool operator==(FpsRange lhs, FpsRange rhs) { + return isApproxEqual(lhs.min, rhs.min) && isApproxEqual(lhs.max, rhs.max); +} + +inline bool operator!=(FpsRange lhs, FpsRange rhs) { + return !(lhs == rhs); +} + } // namespace fps_approx_ops +inline bool FpsRange::includes(Fps fps) const { + using fps_approx_ops::operator<=; + return min <= fps && fps <= max; +} + struct FpsApproxEqual { bool operator()(Fps lhs, Fps rhs) const { return isApproxEqual(lhs, rhs); } }; @@ -125,4 +146,9 @@ inline std::ostream& operator<<(std::ostream& stream, Fps fps) { return stream << to_string(fps); } +inline std::string to_string(FpsRange range) { + const auto [min, max] = range; + return base::StringPrintf("[%s, %s]", to_string(min).c_str(), to_string(max).c_str()); +} + } // namespace android diff --git a/services/surfaceflinger/tests/unittests/FpsTest.cpp b/services/surfaceflinger/tests/unittests/FpsTest.cpp index 88b74d2a22..2193c9dd76 100644 --- a/services/surfaceflinger/tests/unittests/FpsTest.cpp +++ b/services/surfaceflinger/tests/unittests/FpsTest.cpp @@ -68,4 +68,14 @@ TEST(FpsTest, getIntValue) { EXPECT_EQ(31, (30.5_Hz).getIntValue()); } +TEST(FpsTest, range) { + const auto fps = Fps::fromPeriodNsecs(16'666'665); + + EXPECT_TRUE((FpsRange{60.000004_Hz, 60.000004_Hz}.includes(fps))); + EXPECT_TRUE((FpsRange{59_Hz, 60.1_Hz}.includes(fps))); + EXPECT_FALSE((FpsRange{75_Hz, 90_Hz}.includes(fps))); + EXPECT_FALSE((FpsRange{60.0011_Hz, 90_Hz}.includes(fps))); + EXPECT_FALSE((FpsRange{50_Hz, 59.998_Hz}.includes(fps))); +} + } // namespace android diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 4efcc051bb..9143d61145 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -834,17 +834,6 @@ TEST_F(RefreshRateConfigsTest, twoModes_getBestRefreshRate_Explicit) { EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); } -TEST_F(RefreshRateConfigsTest, testInPolicy) { - const auto refreshRate = - asRefreshRate(createDisplayMode(kModeId60, Fps::fromPeriodNsecs(16'666'665))); - - EXPECT_TRUE(refreshRate.inPolicy(60.000004_Hz, 60.000004_Hz)); - EXPECT_TRUE(refreshRate.inPolicy(59_Hz, 60.1_Hz)); - EXPECT_FALSE(refreshRate.inPolicy(75_Hz, 90_Hz)); - EXPECT_FALSE(refreshRate.inPolicy(60.0011_Hz, 90_Hz)); - EXPECT_FALSE(refreshRate.inPolicy(50_Hz, 59.998_Hz)); -} - TEST_F(RefreshRateConfigsTest, getBestRefreshRate_75HzContent) { TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); -- cgit v1.2.3-59-g8ed1b From 206996f064f098b80522f9666863fe412b956536 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Thu, 20 Jan 2022 13:21:57 -0800 Subject: FTL: Refine container semantics Allow constructing StaticVector and SmallVector by moving smaller convertible vectors, which so far incurred a copy. Allow the same copy/move conversion for SmallMap. Consistently with StaticVector, do not require assignable elements for the SmallVector to be assignable, which notably enables SmallMap to be assignable despite its const keys. Allow comparison of convertible containers. Bug: 185536303 Test: ftl_test Change-Id: I35923e794ef26178dc3072f514dea7ad5600bc15 --- include/ftl/details/array_traits.h | 62 ++++++++--- include/ftl/small_map.h | 7 ++ include/ftl/small_vector.h | 84 +++++++++++++-- include/ftl/static_vector.h | 42 ++++++-- libs/ftl/small_map_test.cpp | 27 +++++ libs/ftl/small_vector_test.cpp | 211 +++++++++++++++++++++++++++++++++---- libs/ftl/static_vector_test.cpp | 97 ++++++++++++++--- 7 files changed, 460 insertions(+), 70 deletions(-) diff --git a/include/ftl/details/array_traits.h b/include/ftl/details/array_traits.h index 16e63eca74..5234c383a7 100644 --- a/include/ftl/details/array_traits.h +++ b/include/ftl/details/array_traits.h @@ -42,7 +42,7 @@ struct ArrayTraits { using const_reverse_iterator = std::reverse_iterator; template - static pointer construct_at(const_iterator it, Args&&... args) { + static constexpr pointer construct_at(const_iterator it, Args&&... args) { void* const ptr = const_cast(static_cast(it)); if constexpr (std::is_constructible_v) { // TODO: Replace with std::construct_at in C++20. @@ -52,6 +52,42 @@ struct ArrayTraits { return new (ptr) value_type{std::forward(args)...}; } } + + // TODO: Make constexpr in C++20. + template + static reference replace_at(const_iterator it, Args&&... args) { + value_type element{std::forward(args)...}; + return replace_at(it, std::move(element)); + } + + // TODO: Make constexpr in C++20. + static reference replace_at(const_iterator it, value_type&& value) { + std::destroy_at(it); + // This is only safe because exceptions are disabled. + return *construct_at(it, std::move(value)); + } + + // TODO: Make constexpr in C++20. + static void in_place_swap(reference a, reference b) { + value_type c{std::move(a)}; + replace_at(&a, std::move(b)); + replace_at(&b, std::move(c)); + } + + // TODO: Make constexpr in C++20. + static void in_place_swap_ranges(iterator first1, iterator last1, iterator first2) { + while (first1 != last1) { + in_place_swap(*first1++, *first2++); + } + } + + // TODO: Replace with std::uninitialized_copy in C++20. + template + static void uninitialized_copy(Iterator first, Iterator last, const_iterator out) { + while (first != last) { + construct_at(out++, *first++); + } + } }; // CRTP mixin to define iterator functions in terms of non-const Self::begin and Self::end. @@ -101,33 +137,33 @@ class ArrayIterators { // TODO: Replace with operator<=> in C++20. template