Merge "Correct assertNotifyMotionWasNotCalled check"
diff --git a/data/etc/android.software.opengles.deqp.level-2020-03-01.xml b/data/etc/android.software.opengles.deqp.level-2020-03-01.xml
new file mode 100644
index 0000000..f11e0bb
--- /dev/null
+++ b/data/etc/android.software.opengles.deqp.level-2020-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This is the standard feature indicating that the device passes OpenGL ES
+ dEQP tests associated with date 2020-03-01 (0x07E40301). -->
+<permissions>
+ <feature name="android.software.opengles.deqp.level" version="132383489" />
+</permissions>
diff --git a/data/etc/android.software.opengles.deqp.level-2021-03-01.xml b/data/etc/android.software.opengles.deqp.level-2021-03-01.xml
new file mode 100644
index 0000000..b60697d
--- /dev/null
+++ b/data/etc/android.software.opengles.deqp.level-2021-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This is the standard feature indicating that the device passes OpenGL ES
+ dEQP tests associated with date 2021-03-01 (0x07E50301). -->
+<permissions>
+ <feature name="android.software.opengles.deqp.level" version="132449025" />
+</permissions>
diff --git a/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml
index 9c67d4a..d3ad45a 100644
--- a/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml
+++ b/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<!-- This is the standard feature indicating that the device passes Vulkan deQP
+<!-- This is the standard feature indicating that the device passes Vulkan dEQP
tests associated with date 2019-03-01 (0x07E30301). -->
<permissions>
<feature name="android.software.vulkan.deqp.level" version="132317953" />
diff --git a/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml
index 19b269b..84ba389 100644
--- a/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml
+++ b/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<!-- This is the standard feature indicating that the device passes Vulkan deQP
+<!-- This is the standard feature indicating that the device passes Vulkan dEQP
tests associated with date 2020-03-01 (0x07E40301). -->
<permissions>
<feature name="android.software.vulkan.deqp.level" version="132383489" />
diff --git a/data/etc/android.software.vulkan.deqp.level-2021-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2021-03-01.xml
new file mode 100644
index 0000000..ae26269
--- /dev/null
+++ b/data/etc/android.software.vulkan.deqp.level-2021-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This is the standard feature indicating that the device passes Vulkan dEQP
+ tests associated with date 2021-03-01 (0x07E50301). -->
+<permissions>
+ <feature name="android.software.vulkan.deqp.level" version="132449025" />
+</permissions>
diff --git a/data/etc/cec_config.xml b/data/etc/cec_config.xml
deleted file mode 100644
index 480e0ec..0000000
--- a/data/etc/cec_config.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
-<cec-settings>
- <setting name="hdmi_cec_enabled"
- value-type="int"
- user-configurable="true">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="1" />
- </setting>
- <setting name="hdmi_cec_version"
- value-type="int"
- user-configurable="true">
- <allowed-values>
- <value int-value="0x05" />
- <value int-value="0x06" />
- </allowed-values>
- <default-value int-value="0x05" />
- </setting>
- <setting name="send_standby_on_sleep"
- value-type="string"
- user-configurable="true">
- <allowed-values>
- <value string-value="to_tv" />
- <value string-value="broadcast" />
- <value string-value="none" />
- </allowed-values>
- <default-value string-value="to_tv" />
- </setting>
- <setting name="power_state_change_on_active_source_lost"
- value-type="string"
- user-configurable="true">
- <allowed-values>
- <value string-value="none" />
- <value string-value="standby_now" />
- </allowed-values>
- <default-value string-value="none" />
- </setting>
- <setting name="system_audio_mode_muting"
- value-type="int"
- user-configurable="true">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="1" />
- </setting>
-</cec-settings>
diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
index 2d85f90..04167f7 100644
--- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -114,6 +114,13 @@
*/
AIBinder** getR() { return &mBinder; }
+ bool operator!=(const SpAIBinder& rhs) const { return get() != rhs.get(); }
+ bool operator<(const SpAIBinder& rhs) const { return get() < rhs.get(); }
+ bool operator<=(const SpAIBinder& rhs) const { return get() <= rhs.get(); }
+ bool operator==(const SpAIBinder& rhs) const { return get() == rhs.get(); }
+ bool operator>(const SpAIBinder& rhs) const { return get() > rhs.get(); }
+ bool operator>=(const SpAIBinder& rhs) const { return get() >= rhs.get(); }
+
private:
AIBinder* mBinder = nullptr;
};
@@ -200,6 +207,13 @@
~ScopedAParcel() {}
ScopedAParcel(ScopedAParcel&&) = default;
ScopedAParcel& operator=(ScopedAParcel&&) = default;
+
+ bool operator!=(const ScopedAParcel& rhs) const { return get() != rhs.get(); }
+ bool operator<(const ScopedAParcel& rhs) const { return get() < rhs.get(); }
+ bool operator<=(const ScopedAParcel& rhs) const { return get() <= rhs.get(); }
+ bool operator==(const ScopedAParcel& rhs) const { return get() == rhs.get(); }
+ bool operator>(const ScopedAParcel& rhs) const { return get() > rhs.get(); }
+ bool operator>=(const ScopedAParcel& rhs) const { return get() >= rhs.get(); }
};
/**
@@ -323,6 +337,13 @@
~ScopedFileDescriptor() {}
ScopedFileDescriptor(ScopedFileDescriptor&&) = default;
ScopedFileDescriptor& operator=(ScopedFileDescriptor&&) = default;
+
+ bool operator!=(const ScopedFileDescriptor& rhs) const { return get() != rhs.get(); }
+ bool operator<(const ScopedFileDescriptor& rhs) const { return get() < rhs.get(); }
+ bool operator<=(const ScopedFileDescriptor& rhs) const { return get() <= rhs.get(); }
+ bool operator==(const ScopedFileDescriptor& rhs) const { return get() == rhs.get(); }
+ bool operator>(const ScopedFileDescriptor& rhs) const { return get() > rhs.get(); }
+ bool operator>=(const ScopedFileDescriptor& rhs) const { return get() >= rhs.get(); }
};
} // namespace ndk
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index 4858514..cf2b9e9 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -114,6 +114,25 @@
void reset() { AParcel_reset(mParcel.get()); }
+ inline bool operator!=(const AParcelableHolder& rhs) const {
+ return std::tie(mParcel, mStability) != std::tie(rhs.mParcel, rhs.mStability);
+ }
+ inline bool operator<(const AParcelableHolder& rhs) const {
+ return std::tie(mParcel, mStability) < std::tie(rhs.mParcel, rhs.mStability);
+ }
+ inline bool operator<=(const AParcelableHolder& rhs) const {
+ return std::tie(mParcel, mStability) <= std::tie(rhs.mParcel, rhs.mStability);
+ }
+ inline bool operator==(const AParcelableHolder& rhs) const {
+ return std::tie(mParcel, mStability) == std::tie(rhs.mParcel, rhs.mStability);
+ }
+ inline bool operator>(const AParcelableHolder& rhs) const {
+ return std::tie(mParcel, mStability) > std::tie(rhs.mParcel, rhs.mStability);
+ }
+ inline bool operator>=(const AParcelableHolder& rhs) const {
+ return std::tie(mParcel, mStability) >= std::tie(rhs.mParcel, rhs.mStability);
+ }
+
private:
mutable ndk::ScopedAParcel mParcel;
parcelable_stability_t mStability;
diff --git a/libs/binder/parcel_fuzzer/main.cpp b/libs/binder/parcel_fuzzer/main.cpp
index 386c70b..78606cc 100644
--- a/libs/binder/parcel_fuzzer/main.cpp
+++ b/libs/binder/parcel_fuzzer/main.cpp
@@ -20,12 +20,16 @@
#include "hwbinder.h"
#include "util.h"
+#include <iostream>
+
#include <android-base/logging.h>
#include <fuzzbinder/random_parcel.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <cstdlib>
#include <ctime>
+#include <sys/resource.h>
+#include <sys/time.h>
using android::fillRandomParcel;
@@ -77,7 +81,25 @@
}
}
+size_t getHardMemoryLimit() {
+ struct rlimit limit;
+ CHECK(0 == getrlimit(RLIMIT_AS, &limit)) << errno;
+ return limit.rlim_max;
+}
+
+void setMemoryLimit(size_t cur, size_t max) {
+ const struct rlimit kLimit = {
+ .rlim_cur = cur,
+ .rlim_max = max,
+ };
+ CHECK(0 == setrlimit(RLIMIT_AS, &kLimit)) << errno;
+}
+
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ static constexpr size_t kMemLimit = 1 * 1024 * 1024;
+ size_t hardLimit = getHardMemoryLimit();
+ setMemoryLimit(std::min(kMemLimit, hardLimit), hardLimit);
+
if (size <= 1) return 0; // no use
// avoid timeouts, see b/142617274, b/142473153
@@ -102,5 +124,7 @@
provider.PickValueInArray(fuzzBackend)(std::move(provider));
+ setMemoryLimit(hardLimit, hardLimit);
+
return 0;
}
diff --git a/libs/gralloc/types/include/gralloctypes/Gralloc4.h b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
index 1a7c2c9..2f418ac 100644
--- a/libs/gralloc/types/include/gralloctypes/Gralloc4.h
+++ b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
@@ -32,202 +32,6 @@
#include <android/hardware/graphics/mapper/4.0/IMapper.h>
namespace android {
-
-/**
- * Define equality operators for Stable AIDL types.
- */
-inline bool operator==(const aidl::android::hardware::graphics::common::ExtendableType& lhs,
- const aidl::android::hardware::graphics::common::ExtendableType& rhs) {
- return !std::strcmp(lhs.name.c_str(), rhs.name.c_str()) && lhs.value == rhs.value;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::ExtendableType& lhs,
- const aidl::android::hardware::graphics::common::ExtendableType& rhs) {
- return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::PlaneLayoutComponent& lhs,
- const aidl::android::hardware::graphics::common::PlaneLayoutComponent& rhs) {
- if (lhs.type.name != rhs.type.name) {
- return false;
- }
- if (lhs.type.value != rhs.type.value) {
- return false;
- }
- if (lhs.sizeInBits != rhs.sizeInBits) {
- return false;
- }
- if (lhs.offsetInBits != rhs.offsetInBits) {
- return false;
- }
- return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::PlaneLayoutComponent& lhs,
- const aidl::android::hardware::graphics::common::PlaneLayoutComponent& rhs) {
- return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::Rect& lhs,
- const aidl::android::hardware::graphics::common::Rect& rhs) {
- if (lhs.left != rhs.left) {
- return false;
- }
- if (lhs.top != rhs.top) {
- return false;
- }
- if (lhs.right != rhs.right) {
- return false;
- }
- if (lhs.bottom != rhs.bottom) {
- return false;
- }
- return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::Rect& lhs,
- const aidl::android::hardware::graphics::common::Rect& rhs) {
- return !(lhs == rhs);
-}
-
-inline bool operator==(const std::vector<aidl::android::hardware::graphics::common::Rect>& lhs,
- const std::vector<aidl::android::hardware::graphics::common::Rect>& rhs) {
- if (lhs.size() != rhs.size()) {
- return false;
- }
- for (size_t i = 0; i < lhs.size(); i++) {
- if (lhs[i] != rhs[i]) {
- return false;
- }
- }
- return true;
-}
-
-inline bool operator!=(const std::vector<aidl::android::hardware::graphics::common::Rect>& lhs,
- const std::vector<aidl::android::hardware::graphics::common::Rect>& rhs) {
- return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::PlaneLayout& lhs,
- const aidl::android::hardware::graphics::common::PlaneLayout& rhs) {
- if (lhs.offsetInBytes != rhs.offsetInBytes) {
- return false;
- }
- if (lhs.sampleIncrementInBits != rhs.sampleIncrementInBits) {
- return false;
- }
- if (lhs.strideInBytes != rhs.strideInBytes) {
- return false;
- }
- if (lhs.widthInSamples != rhs.widthInSamples) {
- return false;
- }
- if (lhs.heightInSamples != rhs.heightInSamples) {
- return false;
- }
- if (lhs.totalSizeInBytes != rhs.totalSizeInBytes) {
- return false;
- }
- if (lhs.horizontalSubsampling != rhs.horizontalSubsampling) {
- return false;
- }
- if (lhs.verticalSubsampling != rhs.verticalSubsampling) {
- return false;
- }
- if (lhs.components.size() != rhs.components.size()) {
- return false;
- }
- for (size_t i = 0; i < lhs.components.size(); i++) {
- if (lhs.components[i] != rhs.components[i]) {
- return false;
- }
- }
- return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::PlaneLayout& lhs,
- const aidl::android::hardware::graphics::common::PlaneLayout& rhs) {
- return !(lhs == rhs);
-}
-
-inline bool operator==(const std::vector<aidl::android::hardware::graphics::common::PlaneLayout>& lhs,
- const std::vector<aidl::android::hardware::graphics::common::PlaneLayout>& rhs) {
- if (lhs.size() != rhs.size()) {
- return false;
- }
- for (size_t i = 0; i < lhs.size(); i++) {
- if (lhs[i] != rhs[i]) {
- return false;
- }
- }
- return true;
-}
-
-inline bool operator!=(const std::vector<aidl::android::hardware::graphics::common::PlaneLayout>& lhs,
- const std::vector<aidl::android::hardware::graphics::common::PlaneLayout>& rhs) {
- return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::XyColor& lhs,
- const aidl::android::hardware::graphics::common::XyColor& rhs) {
- if (lhs.x != rhs.x) {
- return false;
- }
- if (lhs.y != rhs.y) {
- return false;
- }
- return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::XyColor& lhs,
- const aidl::android::hardware::graphics::common::XyColor& rhs) {
- return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::Smpte2086& lhs,
- const aidl::android::hardware::graphics::common::Smpte2086& rhs) {
- if (lhs.primaryRed != rhs.primaryRed) {
- return false;
- }
- if (lhs.primaryGreen != rhs.primaryGreen) {
- return false;
- }
- if (lhs.primaryBlue != rhs.primaryBlue) {
- return false;
- }
- if (lhs.whitePoint != rhs.whitePoint) {
- return false;
- }
- if (lhs.maxLuminance != rhs.maxLuminance) {
- return false;
- }
- if (lhs.minLuminance != rhs.minLuminance) {
- return false;
- }
- return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::Smpte2086& lhs,
- const aidl::android::hardware::graphics::common::Smpte2086& rhs) {
- return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::Cta861_3& lhs,
- const aidl::android::hardware::graphics::common::Cta861_3& rhs) {
- if (lhs.maxContentLightLevel != rhs.maxContentLightLevel) {
- return false;
- }
- if (lhs.maxFrameAverageLightLevel != rhs.maxFrameAverageLightLevel) {
- return false;
- }
- return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::Cta861_3& lhs,
- const aidl::android::hardware::graphics::common::Cta861_3& rhs) {
- return !(lhs == rhs);
-}
-
namespace gralloc4 {
#define GRALLOC4_STANDARD_METADATA_TYPE "android.hardware.graphics.common.StandardMetadataType"
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index b9ab561..68000e4 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -123,7 +123,7 @@
mProducer->setMaxDequeuedBufferCount(2);
}
mBufferItemConsumer =
- new BLASTBufferItemConsumer(mConsumer, GraphicBuffer::USAGE_HW_COMPOSER, 1, true);
+ new BLASTBufferItemConsumer(mConsumer, GraphicBuffer::USAGE_HW_COMPOSER, 1, false);
static int32_t id = 0;
auto consumerName = mName + "(BLAST Consumer)" + std::to_string(id);
id++;
@@ -289,6 +289,9 @@
mLastBufferScalingMode = bufferItem.mScalingMode;
t->setBuffer(mSurfaceControl, buffer);
+ t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace));
+ t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata);
+ t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage);
t->setAcquireFence(mSurfaceControl,
bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE);
t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 69f7894..2dacae1 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -17,6 +17,8 @@
#define LOG_TAG "ITransactionCompletedListener"
//#define LOG_NDEBUG 0
+#include <gui/LayerState.h>
+#include <gui/ISurfaceComposer.h>
#include <gui/ITransactionCompletedListener.h>
namespace android {
@@ -90,61 +92,63 @@
return err;
}
-status_t SurfaceStats::writeToParcel(Parcel* output) const {
- status_t err = output->writeStrongBinder(surfaceControl);
- if (err != NO_ERROR) {
- return err;
- }
- err = output->writeInt64(acquireTime);
- if (err != NO_ERROR) {
- return err;
- }
- if (previousReleaseFence) {
- err = output->writeBool(true);
- if (err != NO_ERROR) {
- return err;
- }
- err = output->write(*previousReleaseFence);
- } else {
- err = output->writeBool(false);
- }
- err = output->writeUint32(transformHint);
- if (err != NO_ERROR) {
- return err;
- }
+JankData::JankData() :
+ frameVsyncId(ISurfaceComposer::INVALID_VSYNC_ID),
+ jankType(JankType::None) {
+}
- err = output->writeParcelable(eventStats);
- return err;
+status_t JankData::writeToParcel(Parcel* output) const {
+ SAFE_PARCEL(output->writeInt64, frameVsyncId);
+ SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(jankType));
+ return NO_ERROR;
+}
+
+status_t JankData::readFromParcel(const Parcel* input) {
+ SAFE_PARCEL(input->readInt64, &frameVsyncId);
+ int32_t jankTypeInt;
+ SAFE_PARCEL(input->readInt32, &jankTypeInt);
+ jankType = static_cast<JankType>(jankTypeInt);
+ return NO_ERROR;
+}
+
+status_t SurfaceStats::writeToParcel(Parcel* output) const {
+ SAFE_PARCEL(output->writeStrongBinder, surfaceControl);
+ SAFE_PARCEL(output->writeInt64, acquireTime);
+ if (previousReleaseFence) {
+ SAFE_PARCEL(output->writeBool, true);
+ SAFE_PARCEL(output->write, *previousReleaseFence);
+ } else {
+ SAFE_PARCEL(output->writeBool, false);
+ }
+ SAFE_PARCEL(output->writeUint32, transformHint);
+ SAFE_PARCEL(output->writeParcelable, eventStats);
+ SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(jankData.size()));
+ for (const auto& data : jankData) {
+ SAFE_PARCEL(output->writeParcelable, data);
+ }
+ return NO_ERROR;
}
status_t SurfaceStats::readFromParcel(const Parcel* input) {
- status_t err = input->readStrongBinder(&surfaceControl);
- if (err != NO_ERROR) {
- return err;
- }
- err = input->readInt64(&acquireTime);
- if (err != NO_ERROR) {
- return err;
- }
+ SAFE_PARCEL(input->readStrongBinder, &surfaceControl);
+ SAFE_PARCEL(input->readInt64, &acquireTime);
bool hasFence = false;
- err = input->readBool(&hasFence);
- if (err != NO_ERROR) {
- return err;
- }
+ SAFE_PARCEL(input->readBool, &hasFence);
if (hasFence) {
previousReleaseFence = new Fence();
- err = input->read(*previousReleaseFence);
- if (err != NO_ERROR) {
- return err;
- }
+ SAFE_PARCEL(input->read, *previousReleaseFence);
}
- err = input->readUint32(&transformHint);
- if (err != NO_ERROR) {
- return err;
- }
+ SAFE_PARCEL(input->readUint32, &transformHint);
+ SAFE_PARCEL(input->readParcelable, &eventStats);
- err = input->readParcelable(&eventStats);
- return err;
+ int32_t jankData_size = 0;
+ SAFE_PARCEL_READ_SIZE(input->readInt32, &jankData_size, input->dataSize());
+ for (int i = 0; i < jankData_size; i++) {
+ JankData data;
+ SAFE_PARCEL(input->readParcelable, &data);
+ jankData.push_back(data);
+ }
+ return NO_ERROR;
}
status_t TransactionStats::writeToParcel(Parcel* output) const {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 47a08ab..9ed7d1c 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -125,6 +125,9 @@
return DefaultComposerClient::getComposerClient();
}
+JankDataListener::~JankDataListener() {
+}
+
// ---------------------------------------------------------------------------
// TransactionCompletedListener does not use ANDROID_SINGLETON_STATIC_INSTANCE because it needs
@@ -174,6 +177,23 @@
return callbackId;
}
+void TransactionCompletedListener::addJankListener(const sp<JankDataListener>& listener,
+ sp<SurfaceControl> surfaceControl) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mJankListeners.insert({surfaceControl->getHandle(), listener});
+}
+
+void TransactionCompletedListener::removeJankListener(const sp<JankDataListener>& listener) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ for (auto it = mJankListeners.begin(); it != mJankListeners.end();) {
+ if (it->second == listener) {
+ it = mJankListeners.erase(it);
+ } else {
+ it++;
+ }
+ }
+}
+
void TransactionCompletedListener::addSurfaceControlToCallbacks(
const sp<SurfaceControl>& surfaceControl,
const std::unordered_set<CallbackId>& callbackIds) {
@@ -189,6 +209,7 @@
void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
std::unordered_map<CallbackId, CallbackTranslation> callbacksMap;
+ std::multimap<sp<IBinder>, sp<JankDataListener>> jankListenersMap;
{
std::lock_guard<std::mutex> lock(mMutex);
@@ -204,6 +225,7 @@
* sp<SurfaceControl> that could possibly exist for the callbacks.
*/
callbacksMap = mCallbacks;
+ jankListenersMap = mJankListeners;
for (const auto& transactionStats : listenerStats.transactionStats) {
for (auto& callbackId : transactionStats.callbackIds) {
mCallbacks.erase(callbackId);
@@ -236,6 +258,13 @@
callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
surfaceControlStats);
}
+ for (const auto& surfaceStats : transactionStats.surfaceStats) {
+ if (surfaceStats.jankData.empty()) continue;
+ for (auto it = jankListenersMap.find(surfaceStats.surfaceControl);
+ it != jankListenersMap.end(); it++) {
+ it->second->onJankDataAvailable(surfaceStats.jankData);
+ }
+ }
}
}
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index c58634b..26b3840 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -16,6 +16,8 @@
#pragma once
+#include "JankInfo.h"
+
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
@@ -57,6 +59,27 @@
nsecs_t dequeueReadyTime;
};
+/**
+ * Jank information representing SurfaceFlinger's jank classification about frames for a specific
+ * surface.
+ */
+class JankData : public Parcelable {
+public:
+ status_t writeToParcel(Parcel* output) const override;
+ status_t readFromParcel(const Parcel* input) override;
+
+ JankData();
+ JankData(int64_t frameVsyncId, JankType jankType)
+ : frameVsyncId(frameVsyncId),
+ jankType(jankType) {}
+
+ // Identifier for the frame submitted with Transaction.setFrameTimelineVsyncId
+ int64_t frameVsyncId;
+
+ // The type of jank occurred
+ JankType jankType;
+};
+
class SurfaceStats : public Parcelable {
public:
status_t writeToParcel(Parcel* output) const override;
@@ -64,18 +87,21 @@
SurfaceStats() = default;
SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence,
- uint32_t hint, FrameEventHistoryStats frameEventStats)
+ uint32_t hint, FrameEventHistoryStats frameEventStats,
+ std::vector<JankData> jankData)
: surfaceControl(sc),
acquireTime(time),
previousReleaseFence(prevReleaseFence),
transformHint(hint),
- eventStats(frameEventStats) {}
+ eventStats(frameEventStats),
+ jankData(std::move(jankData)) {}
sp<IBinder> surfaceControl;
nsecs_t acquireTime = -1;
sp<Fence> previousReleaseFence;
uint32_t transformHint = 0;
FrameEventHistoryStats eventStats;
+ std::vector<JankData> jankData;
};
class TransactionStats : public Parcelable {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 2eb97f2..f1845ee 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -619,6 +619,12 @@
// ---------------------------------------------------------------------------
+class JankDataListener : public VirtualLightRefBase {
+public:
+ virtual ~JankDataListener() = 0;
+ virtual void onJankDataAvailable(const std::vector<JankData>& jankData) = 0;
+};
+
class TransactionCompletedListener : public BnTransactionCompletedListener {
TransactionCompletedListener();
@@ -637,6 +643,7 @@
};
std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex);
+ std::multimap<sp<IBinder>, sp<JankDataListener>> mJankListeners GUARDED_BY(mMutex);
public:
static sp<TransactionCompletedListener> getInstance();
@@ -652,6 +659,18 @@
void addSurfaceControlToCallbacks(const sp<SurfaceControl>& surfaceControl,
const std::unordered_set<CallbackId>& callbackIds);
+ /*
+ * Adds a jank listener to be informed about SurfaceFlinger's jank classification for a specific
+ * surface. Jank classifications arrive as part of the transaction callbacks about previous
+ * frames submitted to this Surface.
+ */
+ void addJankListener(const sp<JankDataListener>& listener, sp<SurfaceControl> surfaceControl);
+
+ /**
+ * Removes a jank listener previously added to addJankCallback.
+ */
+ void removeJankListener(const sp<JankDataListener>& listener);
+
// Overrides BnTransactionCompletedListener's onTransactionCompleted
void onTransactionCompleted(ListenerStats stats) override;
};
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index c39b0b5..c75c46c 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -95,6 +95,15 @@
return std::make_unique<InputSurface>(surfaceControl, width, height);
}
+ static std::unique_ptr<InputSurface> makeBlastInputSurface(const sp<SurfaceComposerClient> &scc,
+ int width, int height) {
+ sp<SurfaceControl> surfaceControl =
+ scc->createSurface(String8("Test Buffer Surface"), width, height,
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState);
+ return std::make_unique<InputSurface>(surfaceControl, width, height);
+ }
+
static std::unique_ptr<InputSurface> makeContainerInputSurface(
const sp<SurfaceComposerClient> &scc, int width, int height) {
sp<SurfaceControl> surfaceControl =
@@ -180,13 +189,13 @@
t.apply(true);
}
- void showAt(int x, int y) {
+ void showAt(int x, int y, Rect crop = Rect(0, 0, 100, 100)) {
SurfaceComposerClient::Transaction t;
t.show(mSurfaceControl);
t.setInputWindowInfo(mSurfaceControl, mInputInfo);
t.setLayer(mSurfaceControl, LAYER_BASE);
t.setPosition(mSurfaceControl, x, y);
- t.setCrop_legacy(mSurfaceControl, Rect(0, 0, 100, 100));
+ t.setCrop_legacy(mSurfaceControl, crop);
t.setAlpha(mSurfaceControl, 1);
t.apply(true);
}
@@ -684,4 +693,34 @@
surface->expectTap(1, 10);
}
+TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_bql) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+
+ std::unique_ptr<InputSurface> bufferSurface =
+ InputSurface::makeBufferInputSurface(mComposerClient, 0, 0);
+ bufferSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
+ bufferSurface->mInputInfo.ownerUid = 22222;
+
+ surface->showAt(10, 10);
+ bufferSurface->showAt(50, 50, Rect::EMPTY_RECT);
+
+ injectTap(11, 11);
+ surface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_blast) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+
+ std::unique_ptr<InputSurface> bufferSurface =
+ InputSurface::makeBlastInputSurface(mComposerClient, 0, 0);
+ bufferSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
+ bufferSurface->mInputInfo.ownerUid = 22222;
+
+ surface->showAt(10, 10);
+ bufferSurface->showAt(50, 50, Rect::EMPTY_RECT);
+
+ injectTap(11, 11);
+ surface->expectTap(1, 1);
+}
+
} // namespace android::test
diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl
index 82c220f..6316b59 100644
--- a/libs/input/android/os/IInputConstants.aidl
+++ b/libs/input/android/os/IInputConstants.aidl
@@ -21,4 +21,11 @@
interface IInputConstants
{
const int DEFAULT_DISPATCHING_TIMEOUT_MILLIS = 5000; // 5 seconds
+
+ // Compatibility changes.
+ /**
+ * TODO(b/157929241): remove this before closing the bug. This is needed temporarily
+ * to identify apps that are using this flag.
+ */
+ const long BLOCK_FLAG_SLIPPERY = 157929241;
}
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index b878150..0e74c63 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -81,6 +81,9 @@
"skia/AutoBackendTexture.cpp",
"skia/SkiaRenderEngine.cpp",
"skia/SkiaGLRenderEngine.cpp",
+ "skia/debug/CaptureTimer.cpp",
+ "skia/debug/CommonPool.cpp",
+ "skia/debug/SkiaCapture.cpp",
"skia/filters/BlurFilter.cpp",
"skia/filters/LinearEffect.cpp",
],
@@ -94,6 +97,7 @@
cflags: [
"-fvisibility=hidden",
"-Werror=format",
+ "-Wno-unused-parameter",
],
srcs: [
":librenderengine_sources",
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 11b8e44..ef12fd2 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -31,10 +31,17 @@
#include <ui/Transform.h>
/**
- * Allows to set RenderEngine backend to GLES (default) or Vulkan (NOT yet supported).
+ * Allows to set RenderEngine backend to GLES (default) or SkiaGL (NOT yet supported).
*/
#define PROPERTY_DEBUG_RENDERENGINE_BACKEND "debug.renderengine.backend"
+/**
+ * Turns on recording of skia commands in SkiaGL version of the RE. This property
+ * defines number of milliseconds for the recording to take place. A non zero value
+ * turns on the recording.
+ */
+#define PROPERTY_DEBUG_RENDERENGINE_CAPTURE_SKIA_MS "debug.renderengine.capture_skia_ms"
+
struct ANativeWindowBuffer;
namespace android {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index be6b081..4e9c5af 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -15,19 +15,19 @@
*/
//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include <cstdint>
#include <memory>
#include "SkImageInfo.h"
#include "log/log_main.h"
#include "system/graphics-base-v1.0.h"
-#undef LOG_TAG
-#define LOG_TAG "RenderEngine"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <EGL/egl.h>
#include <EGL/eglext.h>
-#include <GLES2/gl2.h>
#include <sync/sync.h>
#include <ui/BlurRegion.h>
#include <ui/GraphicBuffer.h>
@@ -35,6 +35,8 @@
#include "../gl/GLExtensions.h"
#include "SkiaGLRenderEngine.h"
#include "filters/BlurFilter.h"
+#include "filters/LinearEffect.h"
+#include "skia/debug/SkiaCapture.h"
#include <GrContextOptions.h>
#include <SkCanvas.h>
@@ -46,17 +48,9 @@
#include <SkShadowUtils.h>
#include <SkSurface.h>
#include <gl/GrGLInterface.h>
-#include <sync/sync.h>
-#include <ui/GraphicBuffer.h>
-#include <utils/Trace.h>
#include <cmath>
-#include "../gl/GLExtensions.h"
-#include "SkiaGLRenderEngine.h"
-#include "filters/BlurFilter.h"
-#include "filters/LinearEffect.h"
-
bool checkGlError(const char* op, int lineNumber);
namespace android {
@@ -482,7 +476,7 @@
: ui::Dataspace::SRGB,
mGrContext.get());
- auto canvas = surface->getCanvas();
+ SkCanvas* canvas = mCapture.tryCapture(surface.get());
// Clear the entire canvas with a transparent black to prevent ghost images.
canvas->clear(SK_ColorTRANSPARENT);
canvas->save();
@@ -663,11 +657,12 @@
canvas->restore();
}
+ canvas->restore();
+ mCapture.endCapture();
{
ATRACE_NAME("flush surface");
surface->flush();
}
- canvas->restore();
if (drawFence != nullptr) {
*drawFence = flush();
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index ef06bfa..b53250e 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -35,6 +35,7 @@
#include "SkiaRenderEngine.h"
#include "android-base/macros.h"
#include "filters/BlurFilter.h"
+#include "skia/debug/SkiaCapture.h"
#include "skia/filters/LinearEffect.h"
namespace android {
@@ -116,6 +117,8 @@
sk_sp<GrDirectContext> mProtectedGrContext;
bool mInProtectedContext = false;
+ // Object to capture commands send to Skia.
+ SkiaCapture mCapture;
};
} // namespace skia
diff --git a/libs/renderengine/skia/debug/CaptureTimer.cpp b/libs/renderengine/skia/debug/CaptureTimer.cpp
new file mode 100644
index 0000000..11bcdb8
--- /dev/null
+++ b/libs/renderengine/skia/debug/CaptureTimer.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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 "CaptureTimer.h"
+
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "CommonPool.h"
+
+#include <thread>
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+void CaptureTimer::setTimeout(TimeoutCallback function, std::chrono::milliseconds delay) {
+ this->clear = false;
+ CommonPool::post([=]() {
+ if (this->clear) return;
+ std::this_thread::sleep_for(delay);
+ if (this->clear) return;
+ function();
+ });
+}
+
+void CaptureTimer::stop() {
+ this->clear = true;
+}
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/skia/debug/CaptureTimer.h b/libs/renderengine/skia/debug/CaptureTimer.h
new file mode 100644
index 0000000..a0aa302
--- /dev/null
+++ b/libs/renderengine/skia/debug/CaptureTimer.h
@@ -0,0 +1,43 @@
+/*
+ * 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 <chrono>
+#include <functional>
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+/**
+ * Simple timer that times out after a given delay and executes a void
+ * callback function.
+ */
+class CaptureTimer {
+ bool clear = false;
+
+public:
+ using TimeoutCallback = std::function<void()>;
+ // Start the timeout.
+ void setTimeout(TimeoutCallback function, std::chrono::milliseconds delay);
+ // Stop and clean up.
+ void stop();
+};
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/skia/debug/CommonPool.cpp b/libs/renderengine/skia/debug/CommonPool.cpp
new file mode 100644
index 0000000..bf15300
--- /dev/null
+++ b/libs/renderengine/skia/debug/CommonPool.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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 "CommonPool.h"
+
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <sys/resource.h>
+#include <utils/Trace.h>
+
+#include <system/thread_defs.h>
+#include <array>
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+CommonPool::CommonPool() {
+ ATRACE_CALL();
+
+ CommonPool* pool = this;
+ // Create 2 workers
+ for (int i = 0; i < THREAD_COUNT; i++) {
+ std::thread worker([pool, i] {
+ {
+ std::array<char, 20> name{"reTask"};
+ snprintf(name.data(), name.size(), "reTask%d", i);
+ auto self = pthread_self();
+ pthread_setname_np(self, name.data());
+ setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_FOREGROUND);
+ }
+ pool->workerLoop();
+ });
+ worker.detach();
+ }
+}
+
+CommonPool& CommonPool::instance() {
+ static CommonPool pool;
+ return pool;
+}
+
+void CommonPool::post(Task&& task) {
+ instance().enqueue(std::move(task));
+}
+
+void CommonPool::enqueue(Task&& task) {
+ std::unique_lock lock(mLock);
+ while (mWorkQueue.size() > QUEUE_SIZE) {
+ lock.unlock();
+ ALOGW("Queue is full: %d, waiting before adding more tasks.", QUEUE_SIZE);
+ usleep(100);
+ lock.lock();
+ }
+ mWorkQueue.push(std::move(task));
+ if (mWaitingThreads == THREAD_COUNT || (mWaitingThreads > 0 && mWorkQueue.size() > 1)) {
+ mCondition.notify_one();
+ }
+}
+
+void CommonPool::workerLoop() {
+ std::unique_lock lock(mLock);
+ while (true) {
+ if (mWorkQueue.size() == 0) {
+ mWaitingThreads++;
+ mCondition.wait(lock);
+ mWaitingThreads--;
+ }
+ // Need to double-check that work is still available now that we have the lock
+ // It may have already been grabbed by a different thread
+ while (mWorkQueue.size() > 0) {
+ auto work = mWorkQueue.front();
+ mWorkQueue.pop();
+ lock.unlock();
+ work();
+ lock.lock();
+ }
+ }
+}
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/skia/debug/CommonPool.h b/libs/renderengine/skia/debug/CommonPool.h
new file mode 100644
index 0000000..7fc3d23
--- /dev/null
+++ b/libs/renderengine/skia/debug/CommonPool.h
@@ -0,0 +1,70 @@
+/*
+ * 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 <log/log.h>
+
+#include <condition_variable>
+#include <functional>
+#include <future>
+#include <mutex>
+#include <queue>
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+namespace {
+#define PREVENT_COPY_AND_ASSIGN(Type) \
+private: \
+ Type(const Type&) = delete; \
+ void operator=(const Type&) = delete
+} // namespace
+
+/**
+ * Shamelessly copied from HWUI to execute Skia Capturing on the back thread in
+ * a safe manner.
+ */
+class CommonPool {
+ PREVENT_COPY_AND_ASSIGN(CommonPool);
+
+public:
+ using Task = std::function<void()>;
+ static constexpr auto THREAD_COUNT = 2;
+ static constexpr auto QUEUE_SIZE = 128;
+
+ static void post(Task&& func);
+
+private:
+ static CommonPool& instance();
+
+ CommonPool();
+ ~CommonPool() {}
+
+ void enqueue(Task&&);
+
+ void workerLoop();
+
+ std::mutex mLock;
+ std::condition_variable mCondition;
+ int mWaitingThreads = 0;
+ std::queue<Task> mWorkQueue;
+};
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/skia/debug/README.md b/libs/renderengine/skia/debug/README.md
new file mode 100644
index 0000000..4719e34
--- /dev/null
+++ b/libs/renderengine/skia/debug/README.md
@@ -0,0 +1,17 @@
+This library turns on recording of skia commands in SkiaGL version of the RE.
+The debug property defines number of milliseconds for the recording to take place.
+A non zero value turns on the recording. The recording will stop after MS specified.
+To reset the recording, set the capture_skia_ms flag to a new time. When recording
+is finished, the capture_skia_ms flag will be set to 0 to avoid circular recording.
+
+In order to allow the process to write files onto the device run:
+adb shell setenforce 0
+
+To start recording run:
+adb shell setprop debug.renderengine.capture_skia_ms 1000
+
+File will be stored in the /data/user/ directory on the device:
+adb shell ls -al /data/user/
+
+To retrieve the data from the device:
+adb pull /data/user/re_skiacapture_<timestamp>.mskp
diff --git a/libs/renderengine/skia/debug/SkiaCapture.cpp b/libs/renderengine/skia/debug/SkiaCapture.cpp
new file mode 100644
index 0000000..8006a11
--- /dev/null
+++ b/libs/renderengine/skia/debug/SkiaCapture.cpp
@@ -0,0 +1,144 @@
+/*
+ * 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 "SkiaCapture.h"
+
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+#include <renderengine/RenderEngine.h>
+#include <utils/Trace.h>
+
+#include "CommonPool.h"
+#include "src/utils/SkMultiPictureDocument.h"
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+// The root of the filename to write a recorded SKP to. In order for this file to
+// be written to /data/user/, user must run 'adb shell setenforce 0' in the device.
+static const std::string CAPTURED_FILENAME_BASE = "/data/user/re_skiacapture";
+
+SkiaCapture::~SkiaCapture() {
+ mTimer.stop();
+}
+
+SkCanvas* SkiaCapture::tryCapture(SkSurface* surface) {
+ ATRACE_CALL();
+
+ // If we are not running yet, set up.
+ if (!mCaptureRunning) {
+ mTimerInterval = std::chrono::milliseconds(
+ base::GetIntProperty(PROPERTY_DEBUG_RENDERENGINE_CAPTURE_SKIA_MS, 0));
+ // Set up the multi-frame capture. If we fail to set it up, then just return canvas.
+ // If interval is 0, return surface.
+ if (CC_LIKELY(mTimerInterval == 0ms || !setupMultiFrameCapture())) {
+ return surface->getCanvas();
+ }
+ // Start the new timer. When timer expires, write to file.
+ mTimer.setTimeout(
+ [this] {
+ endCapture();
+ writeToFile();
+ // To avoid going in circles, set the flag to 0. This way the capture can be
+ // restarted just by setting the flag and without restarting the process.
+ base::SetProperty(PROPERTY_DEBUG_RENDERENGINE_CAPTURE_SKIA_MS, "0");
+ },
+ mTimerInterval);
+ }
+
+ // Create a canvas pointer, fill it.
+ SkCanvas* pictureCanvas = mMultiPic->beginPage(surface->width(), surface->height());
+
+ // Setting up an nway canvas is common to any kind of capture.
+ mNwayCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height());
+ mNwayCanvas->addCanvas(surface->getCanvas());
+ mNwayCanvas->addCanvas(pictureCanvas);
+
+ return mNwayCanvas.get();
+}
+
+void SkiaCapture::endCapture() {
+ ATRACE_CALL();
+ // Don't end anything if we are not running.
+ if (!mCaptureRunning) {
+ return;
+ }
+ // Reset the canvas pointer.
+ mNwayCanvas.reset();
+ // End page.
+ if (mMultiPic) {
+ mMultiPic->endPage();
+ }
+}
+
+void SkiaCapture::writeToFile() {
+ ATRACE_CALL();
+ // Pass mMultiPic and mOpenMultiPicStream to a background thread, which will
+ // handle the heavyweight serialization work and destroy them.
+ // mOpenMultiPicStream is released to a bare pointer because keeping it in
+ // a smart pointer makes the lambda non-copyable. The lambda is only called
+ // once, so this is safe.
+ SkFILEWStream* stream = mOpenMultiPicStream.release();
+ CommonPool::post([doc = std::move(mMultiPic), stream] {
+ ALOGD("Finalizing multi frame SKP");
+ doc->close();
+ delete stream;
+ ALOGD("Multi frame SKP complete.");
+ });
+ mCaptureRunning = false;
+}
+
+bool SkiaCapture::setupMultiFrameCapture() {
+ ATRACE_CALL();
+ ALOGD("Set up multi-frame capture, ms = %llu", mTimerInterval.count());
+
+ std::string captureFile;
+ // Attach a timestamp to the file.
+ base::StringAppendF(&captureFile, "%s_%lld.mskp", CAPTURED_FILENAME_BASE.c_str(),
+ std::chrono::steady_clock::now().time_since_epoch().count());
+ auto stream = std::make_unique<SkFILEWStream>(captureFile.c_str());
+ // We own this stream and need to hold it until close() finishes.
+ if (stream->isValid()) {
+ mOpenMultiPicStream = std::move(stream);
+ mSerialContext.reset(new SkSharingSerialContext());
+ SkSerialProcs procs;
+ procs.fImageProc = SkSharingSerialContext::serializeImage;
+ procs.fImageCtx = mSerialContext.get();
+ procs.fTypefaceProc = [](SkTypeface* tf, void* ctx) {
+ return tf->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
+ };
+ // SkDocuments don't take ownership of the streams they write.
+ // we need to keep it until after mMultiPic.close()
+ // procs is passed as a pointer, but just as a method of having an optional default.
+ // procs doesn't need to outlive this Make call.
+ mMultiPic = SkMakeMultiPictureDocument(mOpenMultiPicStream.get(), &procs);
+ mCaptureRunning = true;
+ return true;
+ } else {
+ ALOGE("Could not open \"%s\" for writing.", captureFile.c_str());
+ return false;
+ }
+}
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/skia/debug/SkiaCapture.h b/libs/renderengine/skia/debug/SkiaCapture.h
new file mode 100644
index 0000000..52717a7
--- /dev/null
+++ b/libs/renderengine/skia/debug/SkiaCapture.h
@@ -0,0 +1,70 @@
+/*
+ * 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 <SkDocument.h>
+#include <SkNWayCanvas.h>
+#include <SkSurface.h>
+#include <chrono>
+#include "CaptureTimer.h"
+#include "tools/SkSharingProc.h"
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+using namespace std::chrono_literals;
+
+/**
+ * Class that captures frames that are sent to Skia in Render Engine. It sets up
+ * a multi frame capture and writes it into a file on the device. The capture is
+ * done based on a timer.
+ */
+class SkiaCapture {
+ using Interval = std::chrono::milliseconds;
+
+public:
+ SkiaCapture() {}
+ virtual ~SkiaCapture();
+ // Called every frame. Normally returns early with screen canvas.
+ // But when capture is enabled, returns an nwaycanvas where commands are also recorded.
+ SkCanvas* tryCapture(SkSurface* surface);
+ // Called at the end of every frame.
+ void endCapture();
+
+private:
+ // Performs the first-frame work of a multi frame SKP capture. Returns true if successful.
+ bool setupMultiFrameCapture();
+
+ // Closes the recording and serializes sequence to a file.
+ void writeToFile();
+
+ // Multi frame serialization stream and writer used when serializing more than one frame.
+ std::unique_ptr<SkFILEWStream> mOpenMultiPicStream;
+ sk_sp<SkDocument> mMultiPic;
+ std::unique_ptr<SkSharingSerialContext> mSerialContext;
+ std::unique_ptr<SkNWayCanvas> mNwayCanvas;
+
+ // Capturing and interval control.
+ bool mCaptureRunning = false;
+ CaptureTimer mTimer;
+ Interval mTimerInterval = 0ms;
+};
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 0e11c99..e825742 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -88,6 +88,45 @@
}
};
+class SkiaGLESRenderEngineFactory : public RenderEngineFactory {
+public:
+ std::string name() override { return "SkiaGLESRenderEngineFactory"; }
+
+ std::unique_ptr<renderengine::gl::GLESRenderEngine> createRenderEngine() override {
+ renderengine::RenderEngineCreationArgs reCreationArgs =
+ renderengine::RenderEngineCreationArgs::Builder()
+ .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
+ .setImageCacheSize(1)
+ .setEnableProtectedContext(false)
+ .setPrecacheToneMapperShaderOnly(false)
+ .setSupportsBackgroundBlur(true)
+ .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
+ .setRenderEngineType(renderengine::RenderEngine::RenderEngineType::SKIA_GL)
+ .build();
+ return renderengine::gl::GLESRenderEngine::create(reCreationArgs);
+ }
+};
+
+class SkiaGLESCMRenderEngineFactory : public RenderEngineFactory {
+public:
+ std::string name() override { return "SkiaGLESCMRenderEngineFactory"; }
+
+ std::unique_ptr<renderengine::gl::GLESRenderEngine> createRenderEngine() override {
+ renderengine::RenderEngineCreationArgs reCreationArgs =
+ renderengine::RenderEngineCreationArgs::Builder()
+ .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
+ .setImageCacheSize(1)
+ .setEnableProtectedContext(false)
+ .setPrecacheToneMapperShaderOnly(false)
+ .setSupportsBackgroundBlur(true)
+ .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
+ .setRenderEngineType(renderengine::RenderEngine::RenderEngineType::SKIA_GL)
+ .setUseColorManagerment(true)
+ .build();
+ return renderengine::gl::GLESRenderEngine::create(reCreationArgs);
+ }
+};
+
class RenderEngineTest : public ::testing::TestWithParam<std::shared_ptr<RenderEngineFactory>> {
public:
static sp<GraphicBuffer> allocateDefaultBuffer() {
@@ -1045,7 +1084,9 @@
INSTANTIATE_TEST_SUITE_P(PerRenderEngineType, RenderEngineTest,
testing::Values(std::make_shared<GLESRenderEngineFactory>(),
- std::make_shared<GLESCMRenderEngineFactory>()));
+ std::make_shared<GLESCMRenderEngineFactory>(),
+ std::make_shared<SkiaGLESRenderEngineFactory>(),
+ std::make_shared<SkiaGLESCMRenderEngineFactory>()));
TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) {
const auto& renderEngineFactory = GetParam();
diff --git a/libs/sensorprivacy/OWNERS b/libs/sensorprivacy/OWNERS
new file mode 100644
index 0000000..be955f5
--- /dev/null
+++ b/libs/sensorprivacy/OWNERS
@@ -0,0 +1,3 @@
+cbrubaker@google.com
+evanseverson@google.com
+mpgroover@google.com
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 96e6207..b640e9c 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -58,6 +58,7 @@
"libstatslog",
"libutils",
"libui",
+ "lib-platform-compat-native-api",
],
static_libs: [
"libattestation",
diff --git a/services/inputflinger/benchmarks/Android.bp b/services/inputflinger/benchmarks/Android.bp
index 9abf8b1..bd275a7 100644
--- a/services/inputflinger/benchmarks/Android.bp
+++ b/services/inputflinger/benchmarks/Android.bp
@@ -16,6 +16,7 @@
"libstatslog",
"libui",
"libutils",
+ "lib-platform-compat-native-api",
],
static_libs: [
"libattestation",
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index ff9aac9..d467692 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -47,6 +47,7 @@
"libstatslog",
"libui",
"libutils",
+ "lib-platform-compat-native-api",
],
static_libs: [
"libattestation",
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 91e9536..ed4f05a 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -53,6 +53,8 @@
#include <android-base/stringprintf.h>
#include <android/os/IInputConstants.h>
#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+#include <com/android/internal/compat/IPlatformCompatNative.h>
#include <input/InputDevice.h>
#include <input/InputWindow.h>
#include <log/log.h>
@@ -79,8 +81,10 @@
using android::base::StringPrintf;
using android::os::BlockUntrustedTouchesMode;
+using android::os::IInputConstants;
using android::os::InputEventInjectionResult;
using android::os::InputEventInjectionSync;
+using com::android::internal::compat::IPlatformCompatNative;
namespace android::inputdispatcher {
@@ -422,6 +426,15 @@
return *lhs == *rhs;
}
+static sp<IPlatformCompatNative> getCompatService() {
+ sp<IBinder> service(defaultServiceManager()->getService(String16("platform_compat_native")));
+ if (service == nullptr) {
+ ALOGE("Failed to link to compat service");
+ return nullptr;
+ }
+ return interface_cast<IPlatformCompatNative>(service);
+}
+
// --- InputDispatcher ---
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
@@ -440,7 +453,8 @@
// initialize it here anyways.
mInTouchMode(true),
mMaximumObscuringOpacityForTouch(1.0f),
- mFocusedDisplayId(ADISPLAY_ID_DEFAULT) {
+ mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
+ mCompatService(getCompatService()) {
mLooper = new Looper(false);
mReporter = createInputReporter();
@@ -4010,8 +4024,8 @@
const std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>& handlesPerDisplay) {
{ // acquire lock
std::scoped_lock _l(mLock);
- for (auto const& i : handlesPerDisplay) {
- setInputWindowsLocked(i.second, i.first);
+ for (const auto& [displayId, handles] : handlesPerDisplay) {
+ setInputWindowsLocked(handles, displayId);
}
}
// Wake up poll loop since it may need to make new input dispatching choices.
@@ -4113,6 +4127,18 @@
ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
}
oldWindowHandle->releaseChannel();
+ // To avoid making too many calls into the compat framework, only
+ // check for window flags when windows are going away.
+ // TODO(b/157929241) : delete this. This is only needed temporarily
+ // in order to gather some data about the flag usage
+ if (oldWindowHandle->getInfo()->flags.test(InputWindowInfo::Flag::SLIPPERY)) {
+ ALOGW("%s has FLAG_SLIPPERY. Please report this in b/157929241",
+ oldWindowHandle->getName().c_str());
+ if (mCompatService != nullptr) {
+ mCompatService->reportChangeByUid(IInputConstants::BLOCK_FLAG_SLIPPERY,
+ oldWindowHandle->getInfo()->ownerUid);
+ }
+ }
}
}
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 9aaae74..8f58785 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -32,6 +32,7 @@
#include "TouchedWindow.h"
#include <attestation/HmacKeyManager.h>
+#include <com/android/internal/compat/IPlatformCompatNative.h>
#include <input/Input.h>
#include <input/InputApplication.h>
#include <input/InputTransport.h>
@@ -596,6 +597,7 @@
void traceWaitQueueLength(const sp<Connection>& connection);
sp<InputReporterInterface> mReporter;
+ sp<com::android::internal::compat::IPlatformCompatNative> mCompatService;
};
} // namespace android::inputdispatcher
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index dc99986..325ecfe 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -440,7 +440,7 @@
mName, mFrameTimelineVsyncId);
surfaceFrame->setActualQueueTime(systemTime());
- mQueueItems.push_back({item, std::move(surfaceFrame)});
+ mQueueItems.push_back({item, surfaceFrame});
mQueuedFrames++;
// Wake up any pending callbacks
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index b45900e..5a6b9bc 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -129,10 +129,10 @@
Condition mQueueItemCondition;
struct BufferData {
- BufferData(BufferItem item, std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame)
- : item(item), surfaceFrame(std::move(surfaceFrame)) {}
+ BufferData(BufferItem item, std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame)
+ : item(item), surfaceFrame(surfaceFrame) {}
BufferItem item;
- std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame;
+ std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame;
};
std::vector<BufferData> mQueueItems;
std::atomic<uint64_t> mLastFrameNumberReceived{0};
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 963e541..b6c59cd 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -65,10 +65,70 @@
}
}
+status_t BufferStateLayer::addReleaseFence(const sp<CallbackHandle>& ch,
+ const sp<Fence>& fence) {
+ if (ch == nullptr) {
+ return OK;
+ }
+ if (!ch->previousReleaseFence.get()) {
+ ch->previousReleaseFence = fence;
+ return OK;
+ }
+
+ // Below logic is lifted from ConsumerBase.cpp:
+ // Check status of fences first because merging is expensive.
+ // Merging an invalid fence with any other fence results in an
+ // invalid fence.
+ auto currentStatus = ch->previousReleaseFence->getStatus();
+ if (currentStatus == Fence::Status::Invalid) {
+ ALOGE("Existing fence has invalid state, layer: %s", mName.c_str());
+ return BAD_VALUE;
+ }
+
+ auto incomingStatus = fence->getStatus();
+ if (incomingStatus == Fence::Status::Invalid) {
+ ALOGE("New fence has invalid state, layer: %s", mName.c_str());
+ ch->previousReleaseFence = fence;
+ return BAD_VALUE;
+ }
+
+ // If both fences are signaled or both are unsignaled, we need to merge
+ // them to get an accurate timestamp.
+ if (currentStatus == incomingStatus) {
+ char fenceName[32] = {};
+ snprintf(fenceName, 32, "%.28s", mName.c_str());
+ sp<Fence> mergedFence = Fence::merge(
+ fenceName, ch->previousReleaseFence, fence);
+ if (!mergedFence.get()) {
+ ALOGE("failed to merge release fences, layer: %s", mName.c_str());
+ // synchronization is broken, the best we can do is hope fences
+ // signal in order so the new fence will act like a union
+ ch->previousReleaseFence = fence;
+ return BAD_VALUE;
+ }
+ ch->previousReleaseFence = mergedFence;
+ } else if (incomingStatus == Fence::Status::Unsignaled) {
+ // If one fence has signaled and the other hasn't, the unsignaled
+ // fence will approximately correspond with the correct timestamp.
+ // There's a small race if both fences signal at about the same time
+ // and their statuses are retrieved with unfortunate timing. However,
+ // by this point, they will have both signaled and only the timestamp
+ // will be slightly off; any dependencies after this point will
+ // already have been met.
+ ch->previousReleaseFence = fence;
+ }
+ // else if (currentStatus == Fence::Status::Unsignaled) is a no-op.
+
+ return OK;
+}
+
// -----------------------------------------------------------------------
// Interface implementation for Layer
// -----------------------------------------------------------------------
void BufferStateLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
+ if (!releaseFence->isValid()) {
+ return;
+ }
// The previous release fence notifies the client that SurfaceFlinger is done with the previous
// buffer that was presented on this layer. The first transaction that came in this frame that
// replaced the previous buffer on this layer needs this release fence, because the fence will
@@ -85,12 +145,17 @@
// buffer. It replaces the buffer in the second transaction. The buffer in the second
// transaction will now no longer be presented so it is released immediately and the third
// transaction doesn't need a previous release fence.
+ sp<CallbackHandle> ch;
for (auto& handle : mDrawingState.callbackHandles) {
if (handle->releasePreviousBuffer) {
- handle->previousReleaseFence = releaseFence;
+ ch = handle;
break;
}
}
+ auto status = addReleaseFence(ch, releaseFence);
+ if (status != OK) {
+ ALOGE("Failed to add release fence for layer %s", getName().c_str());
+ }
mPreviousReleaseFence = releaseFence;
@@ -100,14 +165,30 @@
}
}
+void BufferStateLayer::onSurfaceFrameCreated(
+ const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame) {
+ mPendingJankClassifications.emplace_back(surfaceFrame);
+}
+
void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
for (const auto& handle : mDrawingState.callbackHandles) {
handle->transformHint = mTransformHint;
handle->dequeueReadyTime = dequeueReadyTime;
}
+ std::vector<JankData> jankData;
+ jankData.reserve(mPendingJankClassifications.size());
+ while (!mPendingJankClassifications.empty()
+ && mPendingJankClassifications.front()->getJankType()) {
+ std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame =
+ mPendingJankClassifications.front();
+ mPendingJankClassifications.pop_front();
+ jankData.emplace_back(
+ JankData(surfaceFrame->getToken(), surfaceFrame->getJankType().value()));
+ }
+
mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles(
- mDrawingState.callbackHandles);
+ mDrawingState.callbackHandles, jankData);
mDrawingState.callbackHandles = {};
@@ -382,7 +463,7 @@
void BufferStateLayer::forceSendCallbacks() {
mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles(
- mCurrentState.callbackHandles);
+ mCurrentState.callbackHandles, std::vector<JankData>());
}
bool BufferStateLayer::setTransparentRegionHint(const Region& transparent) {
@@ -398,6 +479,10 @@
return Rect(getActiveWidth(s), getActiveHeight(s));
}
+ if (mBufferInfo.mBuffer == nullptr) {
+ return Rect::INVALID_RECT;
+ }
+
// if the display frame is not defined, use the parent bounds as the buffer size.
const auto& p = mDrawingParent.promote();
if (p != nullptr) {
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 42be62a..69b27e4 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -115,6 +115,7 @@
protected:
void gatherBufferInfo() override;
uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
+ void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame);
private:
friend class SlotGenerationTest;
@@ -122,6 +123,8 @@
bool updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime,
nsecs_t requestedPresentTime);
+ status_t addReleaseFence(const sp<CallbackHandle>& ch, const sp<Fence>& releaseFence);
+
uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
bool latchSidebandStream(bool& recomputeVisibleRegions) override;
@@ -158,6 +161,8 @@
bool mReleasePreviousBuffer = false;
nsecs_t mCallbackHandleAcquireTime = -1;
+ std::deque<std::shared_ptr<android::frametimeline::SurfaceFrame>> mPendingJankClassifications;
+
// TODO(marissaw): support sticky transform for LEGACY camera mode
class HwcSlotGenerator : public ClientCache::ErasedRecipient {
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 247ee23..2ac67cb 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -72,6 +72,7 @@
mOutputUsage(GRALLOC_USAGE_HW_COMPOSER),
mProducerSlotSource(0),
mProducerBuffers(),
+ mProducerSlotNeedReallocation(0),
mQueueBufferOutput(),
mSinkBufferWidth(0),
mSinkBufferHeight(0),
@@ -337,10 +338,14 @@
dbgSourceStr(source), *sslot, pslot, result);
uint64_t sourceBit = static_cast<uint64_t>(source) << pslot;
+ // reset producer slot reallocation flag
+ mProducerSlotNeedReallocation &= ~(1ULL << pslot);
+
if ((mProducerSlotSource & (1ULL << pslot)) != sourceBit) {
// This slot was previously dequeued from the other source; must
// re-request the buffer.
- result |= BUFFER_NEEDS_REALLOCATION;
+ mProducerSlotNeedReallocation |= 1ULL << pslot;
+
mProducerSlotSource &= ~(1ULL << pslot);
mProducerSlotSource |= sourceBit;
}
@@ -362,6 +367,9 @@
dbgSourceStr(source), pslot, mProducerBuffers[pslot].get(),
mProducerBuffers[pslot]->getPixelFormat(),
mProducerBuffers[pslot]->getUsage());
+
+ // propagate reallocation to VDS consumer
+ mProducerSlotNeedReallocation |= 1ULL << pslot;
}
return result;
@@ -436,6 +444,11 @@
if (outBufferAge) {
*outBufferAge = 0;
}
+
+ if ((mProducerSlotNeedReallocation & (1ULL << *pslot)) != 0) {
+ result |= BUFFER_NEEDS_REALLOCATION;
+ }
+
return result;
}
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 1974625..fba0e3b 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -176,6 +176,10 @@
uint64_t mProducerSlotSource;
sp<GraphicBuffer> mProducerBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
+ // Need to propagate reallocation to VDS consumer.
+ // Each bit corresponds to a producer slot.
+ uint64_t mProducerSlotNeedReallocation;
+
// The QueueBufferOutput with the latest info from the sink, and with the
// transform hint cleared. Since we defer queueBuffer from the GPU driver
// to the sink, we have to return the previous version.
diff --git a/services/surfaceflinger/Fps.h b/services/surfaceflinger/Fps.h
new file mode 100644
index 0000000..38a9af0
--- /dev/null
+++ b/services/surfaceflinger/Fps.h
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <cmath>
+#include <ostream>
+#include <string>
+
+#include <android-base/stringprintf.h>
+#include <utils/Timers.h>
+
+namespace android {
+
+// Value which represents "frames per second". This class is a wrapper around
+// float, providing some useful utilities, such as comparisons with tolerance
+// and converting between period duruation and frequency.
+class Fps {
+public:
+ static constexpr Fps fromPeriodNsecs(nsecs_t period) { return Fps(1e9f / period, period); }
+
+ Fps() = default;
+ explicit constexpr Fps(float fps)
+ : fps(fps), period(fps == 0.0f ? 0 : static_cast<nsecs_t>(1e9f / fps)) {}
+
+ constexpr float getValue() const { return fps; }
+
+ constexpr nsecs_t getPeriodNsecs() const { return period; }
+
+ bool equalsWithMargin(const Fps& other) const { return std::abs(fps - other.fps) < kMargin; }
+
+ // DO NOT use for std::sort. Instead use comparesLess().
+ bool lessThanWithMargin(const Fps& other) const { return fps + kMargin < other.fps; }
+
+ bool greaterThanWithMargin(const Fps& other) const { return fps > other.fps + kMargin; }
+
+ bool lessThanOrEqualWithMargin(const Fps& other) const { return !greaterThanWithMargin(other); }
+
+ bool greaterThanOrEqualWithMargin(const Fps& other) const { return !lessThanWithMargin(other); }
+
+ bool isValid() const { return fps > 0.0f; }
+
+ int getIntValue() const { return static_cast<int>(std::round(fps)); }
+
+ // Use this comparator for sorting. Using a comparator with margins can
+ // cause std::sort to crash.
+ inline static bool comparesLess(const Fps& left, const Fps& right) {
+ return left.fps < right.fps;
+ }
+
+ // Compares two FPS with margin.
+ // Transitivity is not guaranteed, i.e. a==b and b==c doesn't imply a==c.
+ // DO NOT use with hash maps. Instead use EqualsInBuckets.
+ struct EqualsWithMargin {
+ bool operator()(const Fps& left, const Fps& right) const {
+ return left.equalsWithMargin(right);
+ }
+ };
+
+ // Equals comparator which can be used with hash maps.
+ // It's guaranteed that if two elements are equal, then their hashes are equal.
+ struct EqualsInBuckets {
+ bool operator()(const Fps& left, const Fps& right) const {
+ return left.getBucket() == right.getBucket();
+ }
+ };
+
+ inline friend std::string to_string(const Fps& fps) {
+ return base::StringPrintf("%.2ffps", fps.fps);
+ }
+
+ inline friend std::ostream& operator<<(std::ostream& os, const Fps& fps) {
+ return os << to_string(fps);
+ }
+
+private:
+ friend std::hash<android::Fps>;
+
+ constexpr Fps(float fps, nsecs_t period) : fps(fps), period(period) {}
+
+ float getBucket() const { return std::round(fps / kMargin); }
+
+ static constexpr float kMargin = 0.001f;
+ float fps = 0;
+ nsecs_t period = 0;
+};
+
+static_assert(std::is_trivially_copyable_v<Fps>);
+
+} // namespace android
+
+namespace std {
+template <>
+struct hash<android::Fps> {
+ std::size_t operator()(const android::Fps& fps) const {
+ return std::hash<float>()(fps.getBucket());
+ }
+};
+} // namespace std
\ No newline at end of file
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index b45c213..b09f07a 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -265,8 +265,11 @@
mJankMetadata = jankMetadata;
}
-JankType SurfaceFrame::getJankType() const {
+std::optional<JankType> SurfaceFrame::getJankType() const {
std::lock_guard<std::mutex> lock(mMutex);
+ if (mActuals.presentTime == 0) {
+ return std::nullopt;
+ }
return mJankType;
}
@@ -386,37 +389,36 @@
this->surfaceFrames.reserve(kNumSurfaceFramesInitial);
}
-std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
+std::shared_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
pid_t ownerPid, uid_t ownerUid, std::string layerName, std::string debugName,
std::optional<int64_t> token) {
ATRACE_CALL();
if (!token) {
- return std::make_unique<impl::SurfaceFrame>(ISurfaceComposer::INVALID_VSYNC_ID, ownerPid,
+ return std::make_shared<impl::SurfaceFrame>(ISurfaceComposer::INVALID_VSYNC_ID,ownerPid,
ownerUid, std::move(layerName),
std::move(debugName), PredictionState::None,
TimelineItem());
}
std::optional<TimelineItem> predictions = mTokenManager.getPredictionsForToken(*token);
if (predictions) {
- return std::make_unique<impl::SurfaceFrame>(*token, ownerPid, ownerUid,
+ return std::make_shared<impl::SurfaceFrame>(*token, ownerPid, ownerUid,
std::move(layerName), std::move(debugName),
PredictionState::Valid,
std::move(*predictions));
}
- return std::make_unique<impl::SurfaceFrame>(*token, ownerPid, ownerUid, std::move(layerName),
+ return std::make_shared<impl::SurfaceFrame>(*token, ownerPid, ownerUid, std::move(layerName),
std::move(debugName), PredictionState::Expired,
TimelineItem());
}
void FrameTimeline::addSurfaceFrame(
- std::unique_ptr<android::frametimeline::SurfaceFrame> surfaceFrame,
+ std::shared_ptr<android::frametimeline::SurfaceFrame> surfaceFrame,
SurfaceFrame::PresentState state) {
ATRACE_CALL();
surfaceFrame->setPresentState(state);
- std::unique_ptr<impl::SurfaceFrame> implSurfaceFrame(
- static_cast<impl::SurfaceFrame*>(surfaceFrame.release()));
std::lock_guard<std::mutex> lock(mMutex);
- mCurrentDisplayFrame->surfaceFrames.push_back(std::move(implSurfaceFrame));
+ mCurrentDisplayFrame->surfaceFrames.push_back(
+ std::static_pointer_cast<impl::SurfaceFrame>(surfaceFrame));
}
void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime) {
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index fe83ebf..084935b 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -120,6 +120,12 @@
virtual void setActualStartTime(nsecs_t actualStartTime) = 0;
virtual void setActualQueueTime(nsecs_t actualQueueTime) = 0;
virtual void setAcquireFenceTime(nsecs_t acquireFenceTime) = 0;
+
+ // Retrieves jank classification, if it's already been classified.
+ virtual std::optional<JankType> getJankType() const = 0;
+
+ // Token identifying the frame.
+ virtual int64_t getToken() const = 0;
};
/*
@@ -138,13 +144,13 @@
// Create a new surface frame, set the predictions based on a token and return it to the caller.
// Sets the PredictionState of SurfaceFrame.
// Debug name is the human-readable debugging string for dumpsys.
- virtual std::unique_ptr<SurfaceFrame> createSurfaceFrameForToken(
+ virtual std::shared_ptr<SurfaceFrame> createSurfaceFrameForToken(
pid_t ownerPid, uid_t ownerUid, std::string layerName, std::string debugName,
std::optional<int64_t> token) = 0;
// Adds a new SurfaceFrame to the current DisplayFrame. Frames from multiple layers can be
// composited into one display frame.
- virtual void addSurfaceFrame(std::unique_ptr<SurfaceFrame> surfaceFrame,
+ virtual void addSurfaceFrame(std::shared_ptr<SurfaceFrame> surfaceFrame,
SurfaceFrame::PresentState state) = 0;
// The first function called by SF for the current DisplayFrame. Fetches SF predictions based on
@@ -209,8 +215,8 @@
PresentState getPresentState() const override;
PredictionState getPredictionState() const override { return mPredictionState; };
pid_t getOwnerPid() const override { return mOwnerPid; };
- JankType getJankType() const;
- int64_t getToken() const { return mToken; };
+ std::optional<JankType> getJankType() const override;
+ int64_t getToken() const override { return mToken; };
nsecs_t getBaseTime() const;
uid_t getOwnerUid() const { return mOwnerUid; };
const std::string& getName() const { return mLayerName; };
@@ -258,10 +264,10 @@
~FrameTimeline() = default;
frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; }
- std::unique_ptr<frametimeline::SurfaceFrame> createSurfaceFrameForToken(
+ std::shared_ptr<frametimeline::SurfaceFrame> createSurfaceFrameForToken(
pid_t ownerPid, uid_t ownerUid, std::string layerName, std::string debugName,
std::optional<int64_t> token) override;
- void addSurfaceFrame(std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame,
+ void addSurfaceFrame(std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame,
SurfaceFrame::PresentState state) override;
void setSfWakeUp(int64_t token, nsecs_t wakeupTime) override;
void setSfPresent(nsecs_t sfPresentTime,
@@ -299,7 +305,7 @@
TimelineItem surfaceFlingerActuals;
// Collection of predictions and actual values sent over by Layers
- std::vector<std::unique_ptr<SurfaceFrame>> surfaceFrames;
+ std::vector<std::shared_ptr<SurfaceFrame>> surfaceFrames;
PredictionState predictionState = PredictionState::None;
JankType jankType = JankType::None; // Enum for the type of jank
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 90396dd..9407c92 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -74,6 +74,9 @@
#define DEBUG_RESIZE 0
namespace android {
+namespace {
+constexpr int kDumpTableRowLength = 159;
+} // namespace
using base::StringAppendF;
using namespace android::flag_operators;
@@ -903,17 +906,17 @@
? std::nullopt
: std::make_optional(stateToCommit->frameTimelineVsyncId);
- auto surfaceFrame =
+ mSurfaceFrame =
mFlinger->mFrameTimeline->createSurfaceFrameForToken(getOwnerPid(), getOwnerUid(),
mName, mTransactionName,
vsyncId);
- surfaceFrame->setActualQueueTime(stateToCommit->postTime);
+ 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
- surfaceFrame->setAcquireFenceTime(stateToCommit->postTime);
+ mSurfaceFrame->setAcquireFenceTime(stateToCommit->postTime);
- mSurfaceFrame = std::move(surfaceFrame);
+ onSurfaceFrameCreated(mSurfaceFrame);
}
mCurrentState.modified = false;
@@ -1059,7 +1062,7 @@
void Layer::commitTransaction(const State& stateToCommit) {
mDrawingState = stateToCommit;
- mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mSurfaceFrame), PresentState::Presented);
+ mFlinger->mFrameTimeline->addSurfaceFrame(mSurfaceFrame, PresentState::Presented);
}
uint32_t Layer::getTransactionFlags(uint32_t flags) {
@@ -1276,7 +1279,8 @@
t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
if (!allowNonRectPreservingTransforms && !t.preserveRects()) {
- ALOGW("Attempt to set rotation matrix without permission ACCESS_SURFACE_FLINGER ignored");
+ ALOGW("Attempt to set rotation matrix without permission ACCESS_SURFACE_FLINGER nor "
+ "ROTATE_SURFACE_FLINGER ignored");
return false;
}
mCurrentState.sequence++;
@@ -1425,7 +1429,8 @@
// First traverse the tree and count how many layers has votes
int layersWithVote = 0;
traverseTree([&layersWithVote](Layer* layer) {
- const auto layerVotedWithDefaultCompatibility = layer->mCurrentState.frameRate.rate > 0 &&
+ const auto layerVotedWithDefaultCompatibility =
+ layer->mCurrentState.frameRate.rate.isValid() &&
layer->mCurrentState.frameRate.type == FrameRateCompatibility::Default;
const auto layerVotedWithNoVote =
layer->mCurrentState.frameRate.type == FrameRateCompatibility::NoVote;
@@ -1486,14 +1491,14 @@
Layer::FrameRate Layer::getFrameRateForLayerTree() const {
const auto frameRate = getDrawingState().frameRate;
- if (frameRate.rate > 0 || frameRate.type == FrameRateCompatibility::NoVote) {
+ if (frameRate.rate.isValid() || frameRate.type == FrameRateCompatibility::NoVote) {
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
if (getDrawingState().treeHasFrameRateVote) {
- return {0, FrameRateCompatibility::NoVote};
+ return {Fps(0.0f), FrameRateCompatibility::NoVote};
}
return frameRate;
@@ -1621,11 +1626,8 @@
}
void Layer::miniDumpHeader(std::string& result) {
- result.append("-------------------------------");
- result.append("-------------------------------");
- result.append("-------------------------------");
- result.append("-------------------------------");
- result.append("-------------------\n");
+ result.append(kDumpTableRowLength, '-');
+ result.append("\n");
result.append(" Layer name\n");
result.append(" Z | ");
result.append(" Window Type | ");
@@ -1633,12 +1635,9 @@
result.append(" Transform | ");
result.append(" Disp Frame (LTRB) | ");
result.append(" Source Crop (LTRB) | ");
- result.append(" Frame Rate (Explicit) [Focused]\n");
- result.append("-------------------------------");
- result.append("-------------------------------");
- result.append("-------------------------------");
- result.append("-------------------------------");
- result.append("-------------------\n");
+ result.append(" Frame Rate (Explicit) (Seamlessness) [Focused]\n");
+ result.append(kDumpTableRowLength, '-');
+ result.append("\n");
}
std::string Layer::frameRateCompatibilityString(Layer::FrameRateCompatibility compatibility) {
@@ -1687,23 +1686,20 @@
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 != 0 ||
+ if (layerState.frameRate.rate.isValid() ||
layerState.frameRate.type != FrameRateCompatibility::Default) {
- StringAppendF(&result, "% 6.2ffps %15s seamless=%s", layerState.frameRate.rate,
+ StringAppendF(&result, "%s %15s %17s", to_string(layerState.frameRate.rate).c_str(),
frameRateCompatibilityString(layerState.frameRate.type).c_str(),
toString(layerState.frameRate.seamlessness).c_str());
} else {
- StringAppendF(&result, " ");
+ result.append(41, ' ');
}
const auto focused = isLayerFocusedBasedOnPriority(getFrameRateSelectionPriority());
StringAppendF(&result, " [%s]\n", focused ? "*" : " ");
- result.append("- - - - - - - - - - - - - - - - ");
- result.append("- - - - - - - - - - - - - - - - ");
- result.append("- - - - - - - - - - - - - - - - ");
- result.append("- - - - - - - - - - - - - - - - ");
- result.append("- - - - - - - -\n");
+ result.append(kDumpTableRowLength, '-');
+ result.append("\n");
}
void Layer::dumpFrameStats(std::string& result) const {
@@ -2436,27 +2432,7 @@
return mRemovedFromCurrentState;
}
-InputWindowInfo Layer::fillInputInfo() {
- if (!hasInputInfo()) {
- mDrawingState.inputInfo.name = getName();
- mDrawingState.inputInfo.ownerUid = mCallingUid;
- mDrawingState.inputInfo.ownerPid = mCallingPid;
- mDrawingState.inputInfo.inputFeatures = InputWindowInfo::Feature::NO_INPUT_CHANNEL;
- mDrawingState.inputInfo.flags = InputWindowInfo::Flag::NOT_TOUCH_MODAL;
- mDrawingState.inputInfo.displayId = getLayerStack();
- }
-
- InputWindowInfo info = mDrawingState.inputInfo;
- info.id = sequence;
-
- if (info.displayId == ADISPLAY_ID_NONE) {
- info.displayId = getLayerStack();
- }
-
- ui::Transform t = getTransform();
- int32_t xSurfaceInset = info.surfaceInset;
- int32_t ySurfaceInset = info.surfaceInset;
-
+void Layer::fillInputFrameInfo(InputWindowInfo& info) {
// Transform layer size to screen space and inset it by surface insets.
// If this is a portal window, set the touchableRegion to the layerBounds.
Rect layerBounds = info.portalToDisplayId == ADISPLAY_ID_NONE
@@ -2466,6 +2442,20 @@
layerBounds = getCroppedBufferSize(getDrawingState());
}
+ if (!layerBounds.isValid()) {
+ // If the layer bounds is empty, set the frame to empty and clear the transform
+ info.frameLeft = 0;
+ info.frameTop = 0;
+ info.frameRight = 0;
+ info.frameBottom = 0;
+ info.transform.reset();
+ return;
+ }
+
+ ui::Transform t = getTransform();
+ int32_t xSurfaceInset = info.surfaceInset;
+ int32_t ySurfaceInset = info.surfaceInset;
+
const float xScale = t.getScaleX();
const float yScale = t.getScaleY();
if (xScale != 1.0f || yScale != 1.0f) {
@@ -2532,6 +2522,27 @@
// Position the touchable region relative to frame screen location and restrict it to frame
// bounds.
info.touchableRegion = inputTransform.transform(info.touchableRegion);
+}
+
+InputWindowInfo Layer::fillInputInfo() {
+ if (!hasInputInfo()) {
+ mDrawingState.inputInfo.name = getName();
+ mDrawingState.inputInfo.ownerUid = mOwnerUid;
+ mDrawingState.inputInfo.ownerPid = mOwnerPid;
+ mDrawingState.inputInfo.inputFeatures = InputWindowInfo::Feature::NO_INPUT_CHANNEL;
+ mDrawingState.inputInfo.flags = InputWindowInfo::Flag::NOT_TOUCH_MODAL;
+ mDrawingState.inputInfo.displayId = getLayerStack();
+ }
+
+ InputWindowInfo info = mDrawingState.inputInfo;
+ info.id = sequence;
+
+ if (info.displayId == ADISPLAY_ID_NONE) {
+ info.displayId = getLayerStack();
+ }
+
+ fillInputFrameInfo(info);
+
// For compatibility reasons we let layers which can receive input
// receive input before they have actually submitted a buffer. Because
// of this we use canReceiveInput instead of isVisible to check the
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 75d68a1..ac0eb90 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -45,6 +45,7 @@
#include "ClientCache.h"
#include "DisplayHardware/ComposerHal.h"
#include "DisplayHardware/HWComposer.h"
+#include "Fps.h"
#include "FrameTracker.h"
#include "LayerVector.h"
#include "MonitoredProducer.h"
@@ -155,7 +156,7 @@
struct FrameRate {
using Seamlessness = scheduler::Seamlessness;
- float rate;
+ Fps rate;
FrameRateCompatibility type;
Seamlessness seamlessness;
@@ -163,11 +164,12 @@
: rate(0),
type(FrameRateCompatibility::Default),
seamlessness(Seamlessness::Default) {}
- FrameRate(float rate, FrameRateCompatibility type, bool shouldBeSeamless = true)
+ FrameRate(Fps rate, FrameRateCompatibility type, bool shouldBeSeamless = true)
: rate(rate), type(type), seamlessness(getSeamlessness(rate, shouldBeSeamless)) {}
bool operator==(const FrameRate& other) const {
- return rate == other.rate && type == other.type && seamlessness == other.seamlessness;
+ return rate.equalsWithMargin(other.rate) && type == other.type &&
+ seamlessness == other.seamlessness;
}
bool operator!=(const FrameRate& other) const { return !(*this == other); }
@@ -177,8 +179,8 @@
static FrameRateCompatibility convertCompatibility(int8_t compatibility);
private:
- static Seamlessness getSeamlessness(float rate, bool shouldBeSeamless) {
- if (rate == 0.0f) {
+ static Seamlessness getSeamlessness(Fps rate, bool shouldBeSeamless) {
+ if (!rate.isValid()) {
// Refresh rate of 0 is a special value which should reset the vote to
// its default value.
return Seamlessness::Default;
@@ -942,6 +944,7 @@
virtual void commitTransaction(const State& stateToCommit);
virtual bool applyPendingStates(State* stateToCommit);
virtual uint32_t doTransactionResize(uint32_t flags, Layer::State* stateToCommit);
+ virtual void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>&) {}
// Returns mCurrentScaling mode (originating from the
// Client) or mOverrideScalingMode mode (originating from
@@ -1066,7 +1069,7 @@
const InputWindowInfo::Type mWindowType;
// Can only be accessed with the SF state lock held.
- std::unique_ptr<frametimeline::SurfaceFrame> mSurfaceFrame;
+ std::shared_ptr<frametimeline::SurfaceFrame> mSurfaceFrame;
// The owner of the layer. If created from a non system process, it will be the calling uid.
// If created from a system process, the value can be passed in.
@@ -1111,6 +1114,9 @@
// null.
sp<Layer> getRootLayer();
+ // Fills in the frame and transform info for the InputWindowInfo
+ void fillInputFrameInfo(InputWindowInfo& info);
+
// Cached properties computed from drawing state
// Effective transform taking into account parent transforms and any parent scaling, which is
// a transform from the current layer coordinate space to display(screen) coordinate space.
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index f676d5b..f99d54a 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -190,7 +190,7 @@
Mutex::Autolock _l(mFlinger.mStateLock);
mLayer = mClient->getLayerUser(mIBinder);
- mLayer->setFrameRate(Layer::FrameRate(0, Layer::FrameRateCompatibility::NoVote));
+ mLayer->setFrameRate(Layer::FrameRate(Fps(0.0f), Layer::FrameRateCompatibility::NoVote));
// setting Layer's Z requires resorting layersSortedByZ
ssize_t idx = mFlinger.mCurrentState.layersSortedByZ.indexOf(mLayer);
@@ -205,7 +205,7 @@
void RefreshRateOverlay::primeCache() {
auto& allRefreshRates = mFlinger.mRefreshRateConfigs->getAllRefreshRates();
if (allRefreshRates.size() == 1) {
- auto fps = allRefreshRates.begin()->second->getFps();
+ int fps = allRefreshRates.begin()->second->getFps().getIntValue();
half4 color = {LOW_FPS_COLOR, ALPHA};
mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner));
return;
@@ -214,7 +214,7 @@
std::vector<uint32_t> supportedFps;
supportedFps.reserve(allRefreshRates.size());
for (auto& [ignored, refreshRate] : allRefreshRates) {
- supportedFps.push_back(refreshRate->getFps());
+ supportedFps.push_back(refreshRate->getFps().getIntValue());
}
std::sort(supportedFps.begin(), supportedFps.end());
@@ -240,7 +240,7 @@
}
void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) {
- mCurrentFps = refreshRate.getFps();
+ mCurrentFps = refreshRate.getFps().getIntValue();
auto buffer = mBufferCache[*mCurrentFps][mFrame];
mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {},
mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */));
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index c0d00f3..499daad 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -41,7 +41,7 @@
bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) {
// Layers with an explicit vote are always kept active
- if (layer.getFrameRateForLayerTree().rate > 0) {
+ if (layer.getFrameRateForLayerTree().rate.isValid()) {
return true;
}
@@ -86,9 +86,8 @@
LayerHistory::~LayerHistory() = default;
-void LayerHistory::registerLayer(Layer* layer, float /*lowRefreshRate*/, float highRefreshRate,
- LayerVoteType type) {
- const nsecs_t highRefreshRatePeriod = static_cast<nsecs_t>(1e9f / highRefreshRate);
+void LayerHistory::registerLayer(Layer* layer, Fps highRefreshRate, LayerVoteType type) {
+ const nsecs_t highRefreshRatePeriod = highRefreshRate.getPeriodNsecs();
auto info = std::make_unique<LayerInfo>(layer->getName(), highRefreshRatePeriod, type);
std::lock_guard lock(mLock);
mLayerInfos.emplace_back(layer, std::move(info));
@@ -148,7 +147,7 @@
{strong->getName(), vote.type, vote.fps, vote.seamlessness, weight, layerFocused});
if (CC_UNLIKELY(mTraceEnabled)) {
- trace(layer, *info, vote.type, static_cast<int>(std::round(vote.fps)));
+ trace(layer, *info, vote.type, vote.fps.getIntValue());
}
}
@@ -177,7 +176,7 @@
}
}();
- if (frameRate.rate > 0 || voteType == LayerVoteType::NoVote) {
+ if (frameRate.rate.isValid() || voteType == LayerVoteType::NoVote) {
const auto type = layer->isVisible() ? voteType : LayerVoteType::NoVote;
info->setLayerVote({type, frameRate.rate, frameRate.seamlessness});
} else {
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 507ccc6..4214bab 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -46,7 +46,7 @@
~LayerHistory();
// Layers are unregistered when the weak reference expires.
- void registerLayer(Layer*, float lowRefreshRate, float highRefreshRate, LayerVoteType type);
+ void registerLayer(Layer*, Fps highRefreshRate, LayerVoteType type);
// Sets the display size. Client is responsible for synchronization.
void setDisplayArea(uint32_t displayArea) { mDisplayArea = displayArea; }
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 66ac98a..1c0065c 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -38,7 +38,7 @@
: mName(name),
mHighRefreshRatePeriod(highRefreshRatePeriod),
mDefaultVote(defaultVote),
- mLayerVote({defaultVote, 0.0f}),
+ mLayerVote({defaultVote, Fps(0.0f)}),
mRefreshRateHistory(name) {}
void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, LayerUpdateType updateType,
@@ -91,7 +91,8 @@
// Layer is considered frequent if the average frame rate is higher than the threshold
const auto totalTime = mFrameTimes.back().queueTime - it->queueTime;
- return (1e9f * (numFrames - 1)) / totalTime >= MIN_FPS_FOR_FREQUENT_LAYER;
+ return Fps::fromPeriodNsecs(totalTime / (numFrames - 1))
+ .greaterThanOrEqualWithMargin(MIN_FPS_FOR_FREQUENT_LAYER);
}
bool LayerInfo::isAnimating(nsecs_t now) const {
@@ -139,7 +140,7 @@
missingPresentTime = true;
// If there are no presentation timestamps and we haven't calculated
// one in the past then we can't calculate the refresh rate
- if (mLastRefreshRate.reported == 0) {
+ if (!mLastRefreshRate.reported.isValid()) {
return std::nullopt;
}
continue;
@@ -163,7 +164,7 @@
return static_cast<nsecs_t>(averageFrameTime);
}
-std::optional<float> LayerInfo::calculateRefreshRateIfPossible(nsecs_t now) {
+std::optional<Fps> LayerInfo::calculateRefreshRateIfPossible(nsecs_t now) {
static constexpr float MARGIN = 1.0f; // 1Hz
if (!hasEnoughDataForHeuristic()) {
ALOGV("Not enough data");
@@ -172,7 +173,7 @@
const auto averageFrameTime = calculateAverageFrameTime();
if (averageFrameTime.has_value()) {
- const auto refreshRate = 1e9f / *averageFrameTime;
+ const auto refreshRate = Fps::fromPeriodNsecs(*averageFrameTime);
const bool refreshRateConsistent = mRefreshRateHistory.add(refreshRate, now);
if (refreshRateConsistent) {
const auto knownRefreshRate =
@@ -180,22 +181,23 @@
// To avoid oscillation, use the last calculated refresh rate if it is
// close enough
- if (std::abs(mLastRefreshRate.calculated - refreshRate) > MARGIN &&
- mLastRefreshRate.reported != knownRefreshRate) {
+ if (std::abs(mLastRefreshRate.calculated.getValue() - refreshRate.getValue()) >
+ MARGIN &&
+ !mLastRefreshRate.reported.equalsWithMargin(knownRefreshRate)) {
mLastRefreshRate.calculated = refreshRate;
mLastRefreshRate.reported = knownRefreshRate;
}
- ALOGV("%s %.2fHz rounded to nearest known frame rate %.2fHz", mName.c_str(),
- refreshRate, mLastRefreshRate.reported);
+ ALOGV("%s %s rounded to nearest known frame rate %s", mName.c_str(),
+ to_string(refreshRate).c_str(), to_string(mLastRefreshRate.reported).c_str());
} else {
- ALOGV("%s Not stable (%.2fHz) returning last known frame rate %.2fHz", mName.c_str(),
- refreshRate, mLastRefreshRate.reported);
+ ALOGV("%s Not stable (%s) returning last known frame rate %s", mName.c_str(),
+ to_string(refreshRate).c_str(), to_string(mLastRefreshRate.reported).c_str());
}
}
- return mLastRefreshRate.reported == 0 ? std::nullopt
- : std::make_optional(mLastRefreshRate.reported);
+ return mLastRefreshRate.reported.isValid() ? std::make_optional(mLastRefreshRate.reported)
+ : std::nullopt;
}
LayerInfo::LayerVote LayerInfo::getRefreshRateVote(nsecs_t now) {
@@ -207,13 +209,13 @@
if (isAnimating(now)) {
ALOGV("%s is animating", mName.c_str());
mLastRefreshRate.animatingOrInfrequent = true;
- return {LayerHistory::LayerVoteType::Max, 0};
+ return {LayerHistory::LayerVoteType::Max, Fps(0.0f)};
}
if (!isFrequent(now)) {
ALOGV("%s is infrequent", mName.c_str());
mLastRefreshRate.animatingOrInfrequent = true;
- return {LayerHistory::LayerVoteType::Min, 0};
+ return {LayerHistory::LayerVoteType::Min, Fps(0.0f)};
}
// If the layer was previously tagged as animating or infrequent, we clear
@@ -225,12 +227,12 @@
auto refreshRate = calculateRefreshRateIfPossible(now);
if (refreshRate.has_value()) {
- ALOGV("%s calculated refresh rate: %.2f", mName.c_str(), refreshRate.value());
+ ALOGV("%s calculated refresh rate: %s", mName.c_str(), to_string(*refreshRate).c_str());
return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()};
}
ALOGV("%s Max (can't resolve refresh rate)", mName.c_str());
- return {LayerHistory::LayerVoteType::Max, 0};
+ return {LayerHistory::LayerVoteType::Max, Fps(0.0f)};
}
const char* LayerInfo::getTraceTag(android::scheduler::LayerHistory::LayerVoteType type) const {
@@ -256,7 +258,7 @@
mRefreshRates.clear();
}
-bool LayerInfo::RefreshRateHistory::add(float refreshRate, nsecs_t now) {
+bool LayerInfo::RefreshRateHistory::add(Fps refreshRate, nsecs_t now) {
mRefreshRates.push_back({refreshRate, now});
while (mRefreshRates.size() >= HISTORY_SIZE ||
now - mRefreshRates.front().timestamp > HISTORY_DURATION.count()) {
@@ -268,7 +270,7 @@
mHeuristicTraceTagData = makeHeuristicTraceTagData();
}
- ATRACE_INT(mHeuristicTraceTagData->average.c_str(), static_cast<int>(refreshRate));
+ ATRACE_INT(mHeuristicTraceTagData->average.c_str(), refreshRate.getIntValue());
}
return isConsistent();
@@ -279,15 +281,16 @@
const auto max = std::max_element(mRefreshRates.begin(), mRefreshRates.end());
const auto min = std::min_element(mRefreshRates.begin(), mRefreshRates.end());
- const auto consistent = max->refreshRate - min->refreshRate <= MARGIN_FPS;
+ const auto consistent =
+ max->refreshRate.getValue() - min->refreshRate.getValue() < MARGIN_CONSISTENT_FPS;
if (CC_UNLIKELY(sTraceEnabled)) {
if (!mHeuristicTraceTagData.has_value()) {
mHeuristicTraceTagData = makeHeuristicTraceTagData();
}
- ATRACE_INT(mHeuristicTraceTagData->max.c_str(), static_cast<int>(max->refreshRate));
- ATRACE_INT(mHeuristicTraceTagData->min.c_str(), static_cast<int>(min->refreshRate));
+ ATRACE_INT(mHeuristicTraceTagData->max.c_str(), max->refreshRate.getIntValue());
+ ATRACE_INT(mHeuristicTraceTagData->min.c_str(), min->refreshRate.getIntValue());
ATRACE_INT(mHeuristicTraceTagData->consistent.c_str(), consistent);
}
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index e434670..9304e62 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -50,9 +50,9 @@
// is within a threshold. If a layer is infrequent, its average refresh rate is disregarded in
// favor of a low refresh rate.
static constexpr size_t FREQUENT_LAYER_WINDOW_SIZE = 3;
- static constexpr float MIN_FPS_FOR_FREQUENT_LAYER = 10.0f;
+ static constexpr Fps MIN_FPS_FOR_FREQUENT_LAYER{10.0f};
static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS =
- std::chrono::nanoseconds(static_cast<nsecs_t>(1e9f / MIN_FPS_FOR_FREQUENT_LAYER)) + 1ms;
+ std::chrono::nanoseconds(MIN_FPS_FOR_FREQUENT_LAYER.getPeriodNsecs()) + 1ms;
friend class LayerHistoryTest;
@@ -60,7 +60,7 @@
// Holds information about the layer vote
struct LayerVote {
LayerHistory::LayerVoteType type = LayerHistory::LayerVoteType::Heuristic;
- float fps = 0.0f;
+ Fps fps{0.0f};
Seamlessness seamlessness = Seamlessness::Default;
};
@@ -92,7 +92,7 @@
void setDefaultLayerVote(LayerHistory::LayerVoteType type) { mDefaultVote = type; }
// Resets the layer vote to its default.
- void resetLayerVote() { mLayerVote = {mDefaultVote, 0.0f, Seamlessness::Default}; }
+ void resetLayerVote() { mLayerVote = {mDefaultVote, Fps(0.0f), Seamlessness::Default}; }
LayerVote getRefreshRateVote(nsecs_t now);
@@ -130,9 +130,9 @@
// Holds information about the calculated and reported refresh rate
struct RefreshRateHeuristicData {
// Rate calculated on the layer
- float calculated = 0.0f;
+ Fps calculated{0.0f};
// Last reported rate for LayerInfo::getRefreshRate()
- float reported = 0.0f;
+ Fps reported{0.0f};
// Whether the last reported rate for LayerInfo::getRefreshRate()
// was due to animation or infrequent updates
bool animatingOrInfrequent = false;
@@ -151,18 +151,20 @@
void clear();
// Adds a new refresh rate and returns true if it is consistent
- bool add(float refreshRate, nsecs_t now);
+ bool add(Fps refreshRate, nsecs_t now);
private:
friend class LayerHistoryTest;
// Holds the refresh rate when it was calculated
struct RefreshRateData {
- float refreshRate = 0.0f;
+ Fps refreshRate{0.0f};
nsecs_t timestamp = 0;
bool operator<(const RefreshRateData& other) const {
- return refreshRate < other.refreshRate;
+ // We don't need comparison with margins since we are using
+ // this to find the min and max refresh rates.
+ return refreshRate.getValue() < other.refreshRate.getValue();
}
};
@@ -180,13 +182,13 @@
const std::string mName;
mutable std::optional<HeuristicTraceTagData> mHeuristicTraceTagData;
std::deque<RefreshRateData> mRefreshRates;
- static constexpr float MARGIN_FPS = 1.0;
+ static constexpr float MARGIN_CONSISTENT_FPS = 1.0;
};
bool isFrequent(nsecs_t now) const;
bool isAnimating(nsecs_t now) const;
bool hasEnoughDataForHeuristic() const;
- std::optional<float> calculateRefreshRateIfPossible(nsecs_t now);
+ std::optional<Fps> calculateRefreshRateIfPossible(nsecs_t now);
std::optional<nsecs_t> calculateAverageFrameTime() const;
bool isFrameTimeValid(const FrameTimeData&) const;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 83fa20e..4b7251b 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -29,10 +29,10 @@
namespace android::scheduler {
namespace {
std::string formatLayerInfo(const RefreshRateConfigs::LayerRequirement& layer, float weight) {
- return base::StringPrintf("%s (type=%s, weight=%.2f seamlessness=%s) %.2fHz",
- layer.name.c_str(),
+ 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(), layer.desiredRefreshRate);
+ toString(layer.seamlessness).c_str(),
+ to_string(layer.desiredRefreshRate).c_str());
}
} // namespace
@@ -41,7 +41,7 @@
std::string RefreshRate::toString() const {
return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}",
- getConfigId().value(), hwcConfig->getId(), getFps(),
+ getConfigId().value(), hwcConfig->getId(), getFps().getValue(),
hwcConfig->getWidth(), hwcConfig->getHeight(), getConfigGroup());
}
@@ -64,9 +64,9 @@
std::string RefreshRateConfigs::Policy::toString() const {
return base::StringPrintf("default config ID: %d, allowGroupSwitching = %d"
- ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]",
- defaultConfig.value(), allowGroupSwitching, primaryRange.min,
- primaryRange.max, appRequestRange.min, appRequestRange.max);
+ ", primary range: %s, app request range: %s",
+ defaultConfig.value(), allowGroupSwitching,
+ primaryRange.toString().c_str(), appRequestRange.toString().c_str());
}
std::pair<nsecs_t, nsecs_t> RefreshRateConfigs::getDisplayFrames(nsecs_t layerPeriod,
@@ -144,7 +144,8 @@
// move out the of range if layers explicitly request a different refresh
// rate.
const Policy* policy = getCurrentPolicyLocked();
- const bool primaryRangeIsSingleRate = policy->primaryRange.min == policy->primaryRange.max;
+ const bool primaryRangeIsSingleRate =
+ policy->primaryRange.min.equalsWithMargin(policy->primaryRange.max);
if (!globalSignals.touch && globalSignals.idle &&
!(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
@@ -229,17 +230,18 @@
// If the layer wants Max, give higher score to the higher refresh rate
if (layer.vote == LayerVoteType::Max) {
- const auto ratio = scores[i].first->fps / scores.back().first->fps;
+ const auto ratio =
+ scores[i].first->fps.getValue() / scores.back().first->fps.getValue();
// use ratio^2 to get a lower score the more we get further from peak
const auto layerScore = ratio * ratio;
ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
- scores[i].first->name.c_str(), layerScore);
+ scores[i].first->getName().c_str(), layerScore);
scores[i].second += weight * layerScore;
continue;
}
const auto displayPeriod = scores[i].first->hwcConfig->getVsyncPeriod();
- const auto layerPeriod = round<nsecs_t>(1e9f / layer.desiredRefreshRate);
+ const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs();
if (layer.vote == LayerVoteType::ExplicitDefault) {
const auto layerScore = [&]() {
// Find the actual rate the layer will render, assuming
@@ -256,7 +258,7 @@
}();
ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
- scores[i].first->name.c_str(), layerScore);
+ scores[i].first->getName().c_str(), layerScore);
scores[i].second += weight * layerScore;
continue;
}
@@ -297,7 +299,7 @@
constexpr float kSeamedSwitchPenalty = 0.95f;
const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
- scores[i].first->name.c_str(), layerScore);
+ scores[i].first->getName().c_str(), layerScore);
scores[i].second += weight * layerScore * seamlessness;
continue;
}
@@ -331,7 +333,7 @@
const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked();
if (globalSignals.touch && explicitDefaultVoteLayers == 0 &&
- bestRefreshRate->fps < touchRefreshRate.fps) {
+ bestRefreshRate->fps.lessThanWithMargin(touchRefreshRate.fps)) {
setTouchConsidered();
ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str());
return touchRefreshRate;
@@ -347,9 +349,9 @@
float max = begin->second;
for (auto i = begin; i != end; ++i) {
const auto [refreshRate, score] = *i;
- ALOGV("%s scores %.2f", refreshRate->name.c_str(), score);
+ ALOGV("%s scores %.2f", refreshRate->getName().c_str(), score);
- ATRACE_INT(refreshRate->name.c_str(), round<int>(score * 100));
+ ATRACE_INT(refreshRate->getName().c_str(), round<int>(score * 100));
if (score > max * (1 + EPSILON)) {
max = score;
@@ -433,10 +435,10 @@
for (auto configId = HwcConfigIndexType(0); configId.value() < configs.size(); configId++) {
const auto& config = configs.at(static_cast<size_t>(configId.value()));
- const float fps = 1e9f / config->getVsyncPeriod();
mRefreshRates.emplace(configId,
std::make_unique<RefreshRate>(configId, config,
- base::StringPrintf("%.2ffps", fps), fps,
+ Fps::fromPeriodNsecs(
+ config->getVsyncPeriod()),
RefreshRate::ConstructorTag(0)));
if (configId == currentConfigId) {
mCurrentRefreshRate = mRefreshRates.at(configId).get();
@@ -463,8 +465,8 @@
ALOGE("Default config is not in the primary range.");
return false;
}
- return policy.appRequestRange.min <= policy.primaryRange.min &&
- policy.appRequestRange.max >= policy.primaryRange.max;
+ return policy.appRequestRange.min.lessThanOrEqualWithMargin(policy.primaryRange.min) &&
+ policy.appRequestRange.max.greaterThanOrEqualWithMargin(policy.primaryRange.max);
}
status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) {
@@ -550,12 +552,9 @@
// Filter configs based on current policy and sort based on vsync period
const Policy* policy = getCurrentPolicyLocked();
const auto& defaultConfig = mRefreshRates.at(policy->defaultConfig)->hwcConfig;
- ALOGV("constructAvailableRefreshRates: default %d group %d primaryRange=[%.2f %.2f]"
- " appRequestRange=[%.2f %.2f]",
- policy->defaultConfig.value(), defaultConfig->getConfigGroup(), policy->primaryRange.min,
- policy->primaryRange.max, policy->appRequestRange.min, policy->appRequestRange.max);
+ ALOGV("constructAvailableRefreshRates: %s ", policy->toString().c_str());
- auto filterRefreshRates = [&](float min, float max, const char* listName,
+ auto filterRefreshRates = [&](Fps min, Fps max, const char* listName,
std::vector<const RefreshRate*>* outRefreshRates) {
getSortedRefreshRateList(
[&](const RefreshRate& refreshRate) REQUIRES(mLock) {
@@ -572,12 +571,12 @@
outRefreshRates);
LOG_ALWAYS_FATAL_IF(outRefreshRates->empty(),
- "No matching configs for %s range: min=%.0f max=%.0f", listName, min,
- max);
+ "No matching configs for %s range: min=%s max=%s", listName,
+ to_string(min).c_str(), to_string(max).c_str());
auto stringifyRefreshRates = [&]() -> std::string {
std::string str;
for (auto refreshRate : *outRefreshRates) {
- base::StringAppendF(&str, "%s ", refreshRate->name.c_str());
+ base::StringAppendF(&str, "%s ", refreshRate->getName().c_str());
}
return str;
};
@@ -590,39 +589,39 @@
&mAppRequestRefreshRates);
}
-std::vector<float> RefreshRateConfigs::constructKnownFrameRates(
+std::vector<Fps> RefreshRateConfigs::constructKnownFrameRates(
const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
- std::vector<float> knownFrameRates = {24.0f, 30.0f, 45.0f, 60.0f, 72.0f};
+ std::vector<Fps> knownFrameRates = {Fps(24.0f), Fps(30.0f), Fps(45.0f), Fps(60.0f), Fps(72.0f)};
knownFrameRates.reserve(knownFrameRates.size() + configs.size());
// Add all supported refresh rates to the set
for (const auto& config : configs) {
- const auto refreshRate = 1e9f / config->getVsyncPeriod();
+ const auto refreshRate = Fps::fromPeriodNsecs(config->getVsyncPeriod());
knownFrameRates.emplace_back(refreshRate);
}
// Sort and remove duplicates
- const auto frameRatesEqual = [](float a, float b) { return std::abs(a - b) <= 0.01f; };
- std::sort(knownFrameRates.begin(), knownFrameRates.end());
+ std::sort(knownFrameRates.begin(), knownFrameRates.end(), Fps::comparesLess);
knownFrameRates.erase(std::unique(knownFrameRates.begin(), knownFrameRates.end(),
- frameRatesEqual),
+ Fps::EqualsWithMargin()),
knownFrameRates.end());
return knownFrameRates;
}
-float RefreshRateConfigs::findClosestKnownFrameRate(float frameRate) const {
- if (frameRate <= *mKnownFrameRates.begin()) {
+Fps RefreshRateConfigs::findClosestKnownFrameRate(Fps frameRate) const {
+ if (frameRate.lessThanOrEqualWithMargin(*mKnownFrameRates.begin())) {
return *mKnownFrameRates.begin();
}
- if (frameRate >= *std::prev(mKnownFrameRates.end())) {
+ if (frameRate.greaterThanOrEqualWithMargin(*std::prev(mKnownFrameRates.end()))) {
return *std::prev(mKnownFrameRates.end());
}
- auto lowerBound = std::lower_bound(mKnownFrameRates.begin(), mKnownFrameRates.end(), frameRate);
+ auto lowerBound = std::lower_bound(mKnownFrameRates.begin(), mKnownFrameRates.end(), frameRate,
+ Fps::comparesLess);
- const auto distance1 = std::abs(frameRate - *lowerBound);
- const auto distance2 = std::abs(frameRate - *std::prev(lowerBound));
+ const auto distance1 = std::abs((frameRate.getValue() - lowerBound->getValue()));
+ const auto distance2 = std::abs((frameRate.getValue() - std::prev(lowerBound)->getValue()));
return distance1 < distance2 ? *lowerBound : *std::prev(lowerBound);
}
@@ -657,7 +656,7 @@
std::lock_guard lock(mLock);
if (frameRateOverride.frameRateHz != 0) {
- mPreferredRefreshRateForUid[frameRateOverride.uid] = frameRateOverride.frameRateHz;
+ mPreferredRefreshRateForUid[frameRateOverride.uid] = Fps(frameRateOverride.frameRateHz);
} else {
mPreferredRefreshRateForUid.erase(frameRateOverride.uid);
}
@@ -675,7 +674,7 @@
// in DisplayManagerService.getDisplayInfoForFrameRateOverride
constexpr float kThreshold = 0.1f;
const auto refreshRateHz = iter->second;
- const auto numPeriods = mCurrentRefreshRate->getFps() / refreshRateHz;
+ const auto numPeriods = mCurrentRefreshRate->getFps().getValue() / refreshRateHz.getValue();
const auto numPeriodsRounded = std::round(numPeriods);
if (std::abs(numPeriods - numPeriodsRounded) > kThreshold) {
return 1;
@@ -690,7 +689,7 @@
overrides.reserve(mPreferredRefreshRateForUid.size());
for (const auto [uid, frameRate] : mPreferredRefreshRateForUid) {
- overrides.emplace_back(FrameRateOverride{uid, frameRate});
+ overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()});
}
return overrides;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 6e0c0d3..ec7ffe5 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -25,6 +25,7 @@
#include <type_traits>
#include "DisplayHardware/HWComposer.h"
+#include "Fps.h"
#include "HwcStrongTypes.h"
#include "Scheduler/SchedulerUtils.h"
#include "Scheduler/Seamlessness.h"
@@ -64,29 +65,31 @@
public:
RefreshRate(HwcConfigIndexType configId,
- std::shared_ptr<const HWC2::Display::Config> config, std::string name,
- float fps, ConstructorTag)
- : configId(configId), hwcConfig(config), name(std::move(name)), fps(fps) {}
+ std::shared_ptr<const HWC2::Display::Config> config, Fps fps, ConstructorTag)
+ : configId(configId), hwcConfig(config), fps(std::move(fps)) {}
RefreshRate(const RefreshRate&) = delete;
HwcConfigIndexType getConfigId() const { return configId; }
nsecs_t getVsyncPeriod() const { return hwcConfig->getVsyncPeriod(); }
int32_t getConfigGroup() const { return hwcConfig->getConfigGroup(); }
- const std::string& getName() const { return name; }
- float getFps() const { return fps; }
+ std::string getName() const { return to_string(fps); }
+ Fps getFps() const { return fps; }
// Checks whether the fps of this RefreshRate struct is within a given min and max refresh
- // rate passed in. FPS_EPSILON is applied to the boundaries for approximation.
- bool inPolicy(float minRefreshRate, float maxRefreshRate) const {
- return (fps >= (minRefreshRate - FPS_EPSILON) && fps <= (maxRefreshRate + FPS_EPSILON));
+ // rate passed in. Margin of error is applied to the boundaries for approximation.
+ bool inPolicy(Fps minRefreshRate, Fps maxRefreshRate) const {
+ return minRefreshRate.lessThanOrEqualWithMargin(fps) &&
+ fps.lessThanOrEqualWithMargin(maxRefreshRate);
}
bool operator!=(const RefreshRate& other) const {
return configId != other.configId || hwcConfig != other.hwcConfig;
}
- bool operator<(const RefreshRate& other) const { return getFps() < other.getFps(); }
+ bool operator<(const RefreshRate& other) const {
+ return getFps().getValue() < other.getFps().getValue();
+ }
bool operator==(const RefreshRate& other) const { return !(*this != other); }
@@ -96,18 +99,13 @@
friend RefreshRateConfigs;
friend class RefreshRateConfigsTest;
- // The tolerance within which we consider FPS approximately equals.
- static constexpr float FPS_EPSILON = 0.001f;
-
// This config ID corresponds to the position of the config in the vector that is stored
// on the device.
const HwcConfigIndexType configId;
// The config itself
std::shared_ptr<const HWC2::Display::Config> hwcConfig;
- // Human readable name of the refresh rate.
- const std::string name;
// Refresh rate in frames per second
- const float fps = 0;
+ const Fps fps{0.0f};
};
using AllRefreshRatesMapType =
@@ -119,14 +117,19 @@
public:
struct Range {
- float min = 0;
- float max = std::numeric_limits<float>::max();
+ Fps min{0.0f};
+ Fps max{std::numeric_limits<float>::max()};
bool operator==(const Range& other) const {
- return min == other.min && max == other.max;
+ return min.equalsWithMargin(other.min) && max.equalsWithMargin(other.max);
}
bool operator!=(const Range& other) const { return !(*this == other); }
+
+ std::string toString() const {
+ return base::StringPrintf("[%s %s]", to_string(min).c_str(),
+ to_string(max).c_str());
+ }
};
// The default config, used to ensure we only initiate display config switches within the
@@ -221,7 +224,7 @@
// Layer vote type.
LayerVoteType vote = LayerVoteType::NoVote;
// Layer's desired refresh rate, if applicable.
- float desiredRefreshRate = 0.0f;
+ Fps desiredRefreshRate{0.0f};
// If a seamless mode switch is required.
Seamlessness seamlessness = Seamlessness::Default;
// Layer's weight in the range of [0, 1]. The higher the weight the more impact this layer
@@ -232,7 +235,7 @@
bool operator==(const LayerRequirement& other) const {
return name == other.name && vote == other.vote &&
- desiredRefreshRate == other.desiredRefreshRate &&
+ desiredRefreshRate.equalsWithMargin(other.desiredRefreshRate) &&
seamlessness == other.seamlessness && weight == other.weight &&
focused == other.focused;
}
@@ -295,7 +298,7 @@
static std::string layerVoteTypeString(LayerVoteType vote);
// Returns a known frame rate that is the closest to frameRate
- float findClosestKnownFrameRate(float frameRate) const;
+ Fps findClosestKnownFrameRate(Fps frameRate) const;
RefreshRateConfigs(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
HwcConfigIndexType currentConfigId);
@@ -332,7 +335,7 @@
friend class RefreshRateConfigsTest;
void constructAvailableRefreshRates() REQUIRES(mLock);
- static std::vector<float> constructKnownFrameRates(
+ static std::vector<Fps> constructKnownFrameRates(
const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs);
void getSortedRefreshRateList(
@@ -387,7 +390,7 @@
// A mapping between a UID and a preferred refresh rate that this app would
// run at.
- std::unordered_map<uid_t, float> mPreferredRefreshRateForUid GUARDED_BY(mLock);
+ std::unordered_map<uid_t, Fps> mPreferredRefreshRateForUid GUARDED_BY(mLock);
// The min and max refresh rates supported by the device.
// This will not change at runtime.
@@ -398,7 +401,7 @@
// A sorted list of known frame rates that a Heuristic layer will choose
// from based on the closest value.
- const std::vector<float> mKnownFrameRates;
+ const std::vector<Fps> mKnownFrameRates;
};
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index d9e7b37..80f4665 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -18,7 +18,7 @@
#include <numeric>
-#include "Scheduler/RefreshRateConfigs.h"
+#include "Fps.h"
#include "Scheduler/SchedulerUtils.h"
#include "TimeStats/TimeStats.h"
@@ -40,12 +40,10 @@
static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR;
public:
- RefreshRateStats(const RefreshRateConfigs& refreshRateConfigs, TimeStats& timeStats,
- HwcConfigIndexType currentConfigId,
+ RefreshRateStats(TimeStats& timeStats, Fps currentRefreshRate,
android::hardware::graphics::composer::hal::PowerMode currentPowerMode)
- : mRefreshRateConfigs(refreshRateConfigs),
- mTimeStats(timeStats),
- mCurrentConfigMode(currentConfigId),
+ : mTimeStats(timeStats),
+ mCurrentRefreshRate(currentRefreshRate),
mCurrentPowerMode(currentPowerMode) {}
// Sets power mode.
@@ -59,12 +57,12 @@
// Sets config mode. If the mode has changed, it records how much time was spent in the previous
// mode.
- void setConfigMode(HwcConfigIndexType configId) {
- if (mCurrentConfigMode == configId) {
+ void setRefreshRate(Fps currRefreshRate) {
+ if (mCurrentRefreshRate.equalsWithMargin(currRefreshRate)) {
return;
}
flushTime();
- mCurrentConfigMode = configId;
+ mCurrentRefreshRate = currRefreshRate;
}
// Returns a map between human readable refresh rate and number of seconds the device spent in
@@ -79,10 +77,10 @@
// Multiple configs may map to the same name, e.g. "60fps". Add the
// times for such configs together.
for (const auto& [configId, time] : mConfigModesTotalTime) {
- totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(configId).getName()] = 0;
+ totalTime[to_string(configId)] = 0;
}
for (const auto& [configId, time] : mConfigModesTotalTime) {
- totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(configId).getName()] += time;
+ totalTime[to_string(configId)] += time;
}
totalTime["ScreenOff"] = mScreenOffTime;
return totalTime;
@@ -111,12 +109,11 @@
uint32_t fps = 0;
if (mCurrentPowerMode == android::hardware::graphics::composer::hal::PowerMode::ON) {
// Normal power mode is counted under different config modes.
- if (mConfigModesTotalTime.find(mCurrentConfigMode) == mConfigModesTotalTime.end()) {
- mConfigModesTotalTime[mCurrentConfigMode] = 0;
+ if (mConfigModesTotalTime.find(mCurrentRefreshRate) == mConfigModesTotalTime.end()) {
+ mConfigModesTotalTime[mCurrentRefreshRate] = 0;
}
- mConfigModesTotalTime[mCurrentConfigMode] += timeElapsedMs;
- fps = static_cast<uint32_t>(std::round(
- mRefreshRateConfigs.getRefreshRateFromConfigId(mCurrentConfigMode).getFps()));
+ mConfigModesTotalTime[mCurrentRefreshRate] += timeElapsedMs;
+ fps = static_cast<uint32_t>(mCurrentRefreshRate.getIntValue());
} else {
mScreenOffTime += timeElapsedMs;
}
@@ -134,16 +131,13 @@
days, hours, mins, sec, secRemainderMs);
}
- // Keeps information about refresh rate configs that device has.
- const RefreshRateConfigs& mRefreshRateConfigs;
-
// Aggregate refresh rate statistics for telemetry.
TimeStats& mTimeStats;
- HwcConfigIndexType mCurrentConfigMode;
+ Fps mCurrentRefreshRate;
android::hardware::graphics::composer::hal::PowerMode mCurrentPowerMode;
- std::unordered_map<HwcConfigIndexType /* configId */, int64_t /* duration in ms */>
+ std::unordered_map<Fps, int64_t /* duration in ms */, std::hash<Fps>, Fps::EqualsInBuckets>
mConfigModesTotalTime;
int64_t mScreenOffTime = 0;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 52bf483..07411b0 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -510,25 +510,22 @@
void Scheduler::registerLayer(Layer* layer) {
if (!mLayerHistory) return;
- const auto minFps = mRefreshRateConfigs.getMinRefreshRate().getFps();
const auto maxFps = mRefreshRateConfigs.getMaxRefreshRate().getFps();
if (layer->getWindowType() == InputWindowInfo::Type::STATUS_BAR) {
- mLayerHistory->registerLayer(layer, minFps, maxFps,
- scheduler::LayerHistory::LayerVoteType::NoVote);
+ mLayerHistory->registerLayer(layer, maxFps, scheduler::LayerHistory::LayerVoteType::NoVote);
} else if (!mOptions.useContentDetection) {
// If the content detection feature is off, all layers are registered at Max. 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, minFps, maxFps,
- scheduler::LayerHistory::LayerVoteType::Max);
+ mLayerHistory->registerLayer(layer, maxFps, scheduler::LayerHistory::LayerVoteType::Max);
} else {
if (layer->getWindowType() == InputWindowInfo::Type::WALLPAPER) {
// Running Wallpaper at Min is considered as part of content detection.
- mLayerHistory->registerLayer(layer, minFps, maxFps,
+ mLayerHistory->registerLayer(layer, maxFps,
scheduler::LayerHistory::LayerVoteType::Min);
} else {
- mLayerHistory->registerLayer(layer, minFps, maxFps,
+ mLayerHistory->registerLayer(layer, maxFps,
scheduler::LayerHistory::LayerVoteType::Heuristic);
}
}
@@ -618,14 +615,15 @@
// TODO(145561154): cleanup the kernel idle timer implementation and the refresh rate
// magic number
const auto& refreshRate = mRefreshRateConfigs.getCurrentRefreshRate();
- constexpr float FPS_THRESHOLD_FOR_KERNEL_TIMER = 65.0f;
- if (state == TimerState::Reset && refreshRate.getFps() > FPS_THRESHOLD_FOR_KERNEL_TIMER) {
+ constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER{65.0f};
+ if (state == TimerState::Reset &&
+ refreshRate.getFps().greaterThanWithMargin(FPS_THRESHOLD_FOR_KERNEL_TIMER)) {
// If we're not in performance mode then the kernel timer shouldn't do
// anything, as the refresh rate during DPU power collapse will be the
// same.
resyncToHardwareVsync(true /* makeAvailable */, refreshRate.getVsyncPeriod());
} else if (state == TimerState::Expired &&
- refreshRate.getFps() <= FPS_THRESHOLD_FOR_KERNEL_TIMER) {
+ refreshRate.getFps().lessThanOrEqualWithMargin(FPS_THRESHOLD_FOR_KERNEL_TIMER)) {
// Disable HW VSYNC if the timer expired, as we don't need it enabled if
// we're not pushing frames, and if we're in PERFORMANCE mode then we'll
// need to update the VsyncController model anyway.
diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp b/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp
index aac2569..8431323 100644
--- a/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp
@@ -31,15 +31,10 @@
return std::nullopt;
}
-bool fpsEqualsWithMargin(float fpsA, float fpsB) {
- static constexpr float MARGIN = 0.01f;
- return std::abs(fpsA - fpsB) <= MARGIN;
-}
-
-std::vector<float> getRefreshRatesFromConfigs(
+std::vector<android::Fps> getRefreshRatesFromConfigs(
const android::scheduler::RefreshRateConfigs& refreshRateConfigs) {
const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates();
- std::vector<float> refreshRates;
+ std::vector<android::Fps> refreshRates;
refreshRates.reserve(allRefreshRates.size());
for (const auto& [ignored, refreshRate] : allRefreshRates) {
@@ -53,12 +48,12 @@
namespace android::scheduler::impl {
-VsyncConfiguration::VsyncConfiguration(float currentFps) : mRefreshRateFps(currentFps) {}
+VsyncConfiguration::VsyncConfiguration(Fps currentFps) : mRefreshRateFps(currentFps) {}
-PhaseOffsets::VsyncConfigSet VsyncConfiguration::getConfigsForRefreshRate(float fps) const {
+PhaseOffsets::VsyncConfigSet VsyncConfiguration::getConfigsForRefreshRate(Fps fps) const {
const auto iter = std::find_if(mOffsets.begin(), mOffsets.end(),
- [&fps](const std::pair<float, VsyncConfigSet>& candidateFps) {
- return fpsEqualsWithMargin(fps, candidateFps.first);
+ [&fps](const std::pair<Fps, VsyncConfigSet>& candidateFps) {
+ return fps.equalsWithMargin(candidateFps.first);
});
if (iter != mOffsets.end()) {
@@ -67,13 +62,13 @@
// Unknown refresh rate. This might happen if we get a hotplug event for an external display.
// In this case just construct the offset.
- ALOGW("Can't find offset for %.2f fps", fps);
- return constructOffsets(static_cast<nsecs_t>(1e9f / fps));
+ ALOGW("Can't find offset for %s", to_string(fps).c_str());
+ return constructOffsets(fps.getPeriodNsecs());
}
-void VsyncConfiguration::initializeOffsets(const std::vector<float>& refreshRates) {
+void VsyncConfiguration::initializeOffsets(const std::vector<Fps>& refreshRates) {
for (const auto fps : refreshRates) {
- mOffsets.emplace(fps, constructOffsets(static_cast<nsecs_t>(1e9f / fps)));
+ mOffsets.emplace(fps, constructOffsets(fps.getPeriodNsecs()));
}
}
@@ -127,7 +122,7 @@
.value_or(std::numeric_limits<nsecs_t>::max())) {}
PhaseOffsets::PhaseOffsets(
- const std::vector<float>& refreshRates, float currentFps, nsecs_t vsyncPhaseOffsetNs,
+ const std::vector<Fps>& refreshRates, Fps currentFps, nsecs_t vsyncPhaseOffsetNs,
nsecs_t sfVSyncPhaseOffsetNs, std::optional<nsecs_t> earlySfOffsetNs,
std::optional<nsecs_t> earlyGpuSfOffsetNs, std::optional<nsecs_t> earlyAppOffsetNs,
std::optional<nsecs_t> earlyGpuAppOffsetNs, nsecs_t highFpsVsyncPhaseOffsetNs,
@@ -378,10 +373,9 @@
validateSysprops();
}
-WorkDuration::WorkDuration(const std::vector<float>& refreshRates, float currentFps,
- nsecs_t sfDuration, nsecs_t appDuration, nsecs_t sfEarlyDuration,
- nsecs_t appEarlyDuration, nsecs_t sfEarlyGpuDuration,
- nsecs_t appEarlyGpuDuration)
+WorkDuration::WorkDuration(const std::vector<Fps>& refreshRates, Fps currentFps, nsecs_t sfDuration,
+ nsecs_t appDuration, nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
+ nsecs_t sfEarlyGpuDuration, nsecs_t appEarlyGpuDuration)
: VsyncConfiguration(currentFps),
mSfDuration(sfDuration),
mAppDuration(appDuration),
diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.h b/services/surfaceflinger/Scheduler/VsyncConfiguration.h
index c27a25d..a120e97 100644
--- a/services/surfaceflinger/Scheduler/VsyncConfiguration.h
+++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.h
@@ -18,6 +18,9 @@
#include <unordered_map>
+#include <utils/Timers.h>
+
+#include "Fps.h"
#include "RefreshRateConfigs.h"
#include "VsyncModulator.h"
@@ -35,9 +38,9 @@
virtual ~VsyncConfiguration() = default;
virtual VsyncConfigSet getCurrentConfigs() const = 0;
- virtual VsyncConfigSet getConfigsForRefreshRate(float fps) const = 0;
+ virtual VsyncConfigSet getConfigsForRefreshRate(Fps fps) const = 0;
- virtual void setRefreshRateFps(float fps) = 0;
+ virtual void setRefreshRateFps(Fps fps) = 0;
virtual void dump(std::string& result) const = 0;
};
@@ -51,10 +54,10 @@
*/
class VsyncConfiguration : public scheduler::VsyncConfiguration {
public:
- explicit VsyncConfiguration(float currentFps);
+ explicit VsyncConfiguration(Fps currentFps);
// Returns early, early GL, and late offsets for Apps and SF for a given refresh rate.
- VsyncConfigSet getConfigsForRefreshRate(float fps) const override;
+ VsyncConfigSet getConfigsForRefreshRate(Fps fps) const override;
// Returns early, early GL, and late offsets for Apps and SF.
VsyncConfigSet getCurrentConfigs() const override {
@@ -63,17 +66,17 @@
// This function should be called when the device is switching between different
// refresh rates, to properly update the offsets.
- void setRefreshRateFps(float fps) override { mRefreshRateFps = fps; }
+ void setRefreshRateFps(Fps fps) override { mRefreshRateFps = fps; }
// Returns current offsets in human friendly format.
void dump(std::string& result) const override;
protected:
- void initializeOffsets(const std::vector<float>& refreshRates);
+ void initializeOffsets(const std::vector<Fps>& refreshRates);
virtual VsyncConfiguration::VsyncConfigSet constructOffsets(nsecs_t vsyncDuration) const = 0;
- std::unordered_map<float, VsyncConfigSet> mOffsets;
- std::atomic<float> mRefreshRateFps;
+ std::unordered_map<Fps, VsyncConfigSet, std::hash<Fps>, Fps::EqualsInBuckets> mOffsets;
+ std::atomic<Fps> mRefreshRateFps;
};
/*
@@ -86,10 +89,9 @@
protected:
// Used for unit tests
- PhaseOffsets(const std::vector<float>& refreshRates, float currentFps,
- nsecs_t vsyncPhaseOffsetNs, nsecs_t sfVSyncPhaseOffsetNs,
- std::optional<nsecs_t> earlySfOffsetNs, std::optional<nsecs_t> earlyGpuSfOffsetNs,
- std::optional<nsecs_t> earlyAppOffsetNs,
+ PhaseOffsets(const std::vector<Fps>& refreshRates, Fps currentFps, nsecs_t vsyncPhaseOffsetNs,
+ nsecs_t sfVSyncPhaseOffsetNs, std::optional<nsecs_t> earlySfOffsetNs,
+ std::optional<nsecs_t> earlyGpuSfOffsetNs, std::optional<nsecs_t> earlyAppOffsetNs,
std::optional<nsecs_t> earlyGpuAppOffsetNs, nsecs_t highFpsVsyncPhaseOffsetNs,
nsecs_t highFpsSfVSyncPhaseOffsetNs, std::optional<nsecs_t> highFpsEarlySfOffsetNs,
std::optional<nsecs_t> highFpsEarlyGpuSfOffsetNs,
@@ -130,7 +132,7 @@
protected:
// Used for unit tests
- WorkDuration(const std::vector<float>& refreshRates, float currentFps, nsecs_t sfDuration,
+ WorkDuration(const std::vector<Fps>& refreshRates, Fps currentFps, nsecs_t sfDuration,
nsecs_t appDuration, nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
nsecs_t sfEarlyGpuDuration, nsecs_t appEarlyGpuDuration);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 95c9982..e9416d6 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -274,6 +274,7 @@
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 sDump("android.permission.DUMP");
const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled";
@@ -324,6 +325,14 @@
}
}
+bool callingThreadHasRotateSurfaceFlingerAccess() {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ return uid == AID_GRAPHICS || uid == AID_SYSTEM ||
+ PermissionCache::checkPermission(sRotateSurfaceFlinger, pid, uid);
+}
+
SurfaceFlingerBE::SurfaceFlingerBE() : mHwcServiceName(getHwcServiceName()) {}
SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
@@ -921,10 +930,10 @@
}
const nsecs_t period = hwConfig->getVsyncPeriod();
- config.refreshRate = 1e9f / period;
+ config.refreshRate = Fps::fromPeriodNsecs(period).getValue();
const auto vsyncConfigSet =
- mVsyncConfiguration->getConfigsForRefreshRate(config.refreshRate);
+ mVsyncConfiguration->getConfigsForRefreshRate(Fps(config.refreshRate));
config.appVsyncOffset = vsyncConfigSet.late.appOffset;
config.sfVsyncOffset = vsyncConfigSet.late.sfOffset;
config.configGroup = hwConfig->getConfigGroup();
@@ -1042,7 +1051,7 @@
return INVALID_OPERATION;
} else {
const HwcConfigIndexType config(mode);
- const float fps = mRefreshRateConfigs->getRefreshRateFromConfigId(config).getFps();
+ const auto fps = mRefreshRateConfigs->getRefreshRateFromConfigId(config).getFps();
// Keep the old switching type.
const auto allowGroupSwitching =
mRefreshRateConfigs->getCurrentPolicy().allowGroupSwitching;
@@ -1071,16 +1080,17 @@
std::lock_guard<std::mutex> lock(mActiveConfigLock);
mRefreshRateConfigs->setCurrentConfigId(mUpcomingActiveConfig.configId);
- mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId);
display->setActiveConfig(mUpcomingActiveConfig.configId);
auto& refreshRate =
mRefreshRateConfigs->getRefreshRateFromConfigId(mUpcomingActiveConfig.configId);
+ mRefreshRateStats->setRefreshRate(refreshRate.getFps());
+
if (refreshRate.getVsyncPeriod() != oldRefreshRate.getVsyncPeriod()) {
mTimeStats->incrementRefreshRateSwitches();
}
updatePhaseConfiguration(refreshRate);
- ATRACE_INT("ActiveConfigFPS", refreshRate.getFps());
+ ATRACE_INT("ActiveConfigFPS", refreshRate.getFps().getValue());
if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
const nsecs_t vsyncPeriod =
@@ -1138,7 +1148,7 @@
mUpcomingActiveConfig = *desiredActiveConfig;
const auto displayId = display->getPhysicalId();
- ATRACE_INT("ActiveConfigFPS_HWC", refreshRate.getFps());
+ ATRACE_INT("ActiveConfigFPS_HWC", refreshRate.getFps().getValue());
// TODO(b/142753666) use constrains
hal::VsyncPeriodChangeConstraints constraints;
@@ -1617,7 +1627,7 @@
void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hal::HWDisplayId hwcDisplayId,
hal::Connection connection) {
- ALOGV("%s(%d, %" PRIu64 ", %s)", __FUNCTION__, sequenceId, hwcDisplayId,
+ ALOGI("%s(%d, %" PRIu64 ", %s)", __FUNCTION__, sequenceId, hwcDisplayId,
connection == hal::Connection::CONNECTED ? "connected" : "disconnected");
// Ignore events that do not have the right sequenceId.
@@ -1986,12 +1996,14 @@
mScheduler->onDisplayRefreshed(presentTime);
- postFrame();
- postComposition();
-
+ // Set presentation information before calling postComposition, such that jank information from
+ // this' frame classification is already available when sending jank info to clients.
mFrameTimeline->setSfPresent(systemTime(),
std::make_shared<FenceTime>(mPreviousPresentFences[0]));
+ postFrame();
+ postComposition();
+
const bool prevFrameHadClientComposition = mHadClientComposition;
mHadClientComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
@@ -2384,6 +2396,8 @@
}
void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) {
+ ALOGI("Dispatching display hotplug event displayId=%s, connected=%d",
+ to_string(displayId).c_str(), connected);
mScheduler->onHotplugReceived(mAppConnectionHandle, displayId, connected);
mScheduler->onHotplugReceived(mSfConnectionHandle, displayId, connected);
}
@@ -2559,7 +2573,8 @@
}
void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) {
- if (const auto display = getDisplayDeviceLocked(displayToken)) {
+ auto display = getDisplayDeviceLocked(displayToken);
+ if (display) {
display->disconnect();
if (!display->isVirtual()) {
dispatchDisplayHotplugEvent(display->getPhysicalId(), false);
@@ -2567,6 +2582,22 @@
}
mDisplays.erase(displayToken);
+
+ if (display && display->isVirtual()) {
+ static_cast<void>(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.
+ // With blast, the IGBP that is passed to the VirtualDisplaySurface is owned by the
+ // client. When the IGBP is disconnected, its buffer cache in SF will be cleared
+ // via SurfaceComposerClient::doUncacheBufferTransaction. This call from the client
+ // ends up running on the main thread causing a deadlock since setTransactionstate
+ // will try to acquire the mStateLock. Instead we extend the lifetime of
+ // DisplayDevice and destroy it in the main thread without holding the mStateLock.
+ // The display will be disconnected and removed from the mDisplays list so it will
+ // not be accessible.
+ }));
+ }
}
void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken,
@@ -2868,10 +2899,10 @@
std::make_unique<scheduler::RefreshRateConfigs>(getHwComposer().getConfigs(
primaryDisplayId),
currentConfig);
+ const auto& currRefreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(currentConfig);
mRefreshRateStats =
- std::make_unique<scheduler::RefreshRateStats>(*mRefreshRateConfigs, *mTimeStats,
- currentConfig, hal::PowerMode::OFF);
- mRefreshRateStats->setConfigMode(currentConfig);
+ std::make_unique<scheduler::RefreshRateStats>(*mTimeStats, currRefreshRate.getFps(),
+ hal::PowerMode::OFF);
mVsyncConfiguration = getFactory().createVsyncConfiguration(*mRefreshRateConfigs);
mVsyncModulator.emplace(mVsyncConfiguration->getCurrentConfigs());
@@ -2879,8 +2910,7 @@
// start the EventThread
mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this);
const auto configs = mVsyncConfiguration->getCurrentConfigs();
- const nsecs_t vsyncPeriod =
- mRefreshRateConfigs->getRefreshRateFromConfigId(currentConfig).getVsyncPeriod();
+ const nsecs_t vsyncPeriod = currRefreshRate.getVsyncPeriod();
mAppConnectionHandle =
mScheduler->createConnection("app", mFrameTimeline->getTokenManager(),
/*workDuration=*/configs.late.appWorkDuration,
@@ -3652,15 +3682,20 @@
// must now be cropped to a non rectangular 8 sided region.
//
// Of course we can fix this in the future. For now, we are lucky, SurfaceControl is
- // private API, and the WindowManager only uses rotation in one case, which is on a top
- // level layer in which cropping is not an issue.
+ // private API, and arbitrary rotation is used in limited use cases, for instance:
+ // - WindowManager only uses rotation in one case, which is on a top level layer in which
+ // cropping is not an issue.
+ // - Launcher, as a privileged app, uses this to transition an application to PiP
+ // (picture-in-picture) mode.
//
// However given that abuse of rotation matrices could lead to surfaces extending outside
- // of cropped areas, we need to prevent non-root clients without permission ACCESS_SURFACE_FLINGER
- // (a.k.a. everyone except WindowManager and tests) from setting non rectangle preserving
- // transformations.
- if (layer->setMatrix(s.matrix, privileged))
- flags |= eTraversalNeeded;
+ // of cropped areas, we need to prevent non-root clients without permission
+ // ACCESS_SURFACE_FLINGER nor ROTATE_SURFACE_FLINGER
+ // (a.k.a. everyone except WindowManager / tests / Launcher) from setting non rectangle
+ // preserving transformations.
+ bool allowNonRectPreservingTransforms =
+ privileged || callingThreadHasRotateSurfaceFlingerAccess();
+ if (layer->setMatrix(s.matrix, allowNonRectPreservingTransforms)) flags |= eTraversalNeeded;
}
if (what & layer_state_t::eTransparentRegionChanged) {
if (layer->setTransparentRegionHint(s.transparentRegion))
@@ -3775,7 +3810,7 @@
if (what & layer_state_t::eFrameRateChanged) {
if (ValidateFrameRate(s.frameRate, s.frameRateCompatibility,
"SurfaceFlinger::setClientStateLocked") &&
- layer->setFrameRate(Layer::FrameRate(s.frameRate,
+ layer->setFrameRate(Layer::FrameRate(Fps(s.frameRate),
Layer::FrameRate::convertCompatibility(
s.frameRateCompatibility),
s.shouldBeSeamless))) {
@@ -4708,8 +4743,8 @@
const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
std::string fps, xDpi, yDpi;
if (activeConfig) {
- fps = base::StringPrintf("%.2f Hz",
- 1e9f / getHwComposer().getDisplayVsyncPeriod(*displayId));
+ const auto vsyncPeriod = getHwComposer().getDisplayVsyncPeriod(*displayId);
+ fps = base::StringPrintf("%s", to_string(Fps::fromPeriodNsecs(vsyncPeriod)).c_str());
xDpi = base::StringPrintf("%.2f", activeConfig->getDpiX());
yDpi = base::StringPrintf("%.2f", activeConfig->getDpiY());
} else {
@@ -5965,11 +6000,7 @@
}
scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy();
- ALOGV("Setting desired display config specs: defaultConfig: %d primaryRange: [%.0f %.0f]"
- " expandedRange: [%.0f %.0f]",
- currentPolicy.defaultConfig.value(), currentPolicy.primaryRange.min,
- currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min,
- currentPolicy.appRequestRange.max);
+ ALOGV("Setting desired display config specs: %s", currentPolicy.toString().c_str());
// TODO(b/140204874): Leave the event in until we do proper testing with all apps that might
// be depending in this callback.
@@ -6025,8 +6056,8 @@
using Policy = scheduler::RefreshRateConfigs::Policy;
const Policy policy{HwcConfigIndexType(defaultConfig),
allowGroupSwitching,
- {primaryRefreshRateMin, primaryRefreshRateMax},
- {appRequestRefreshRateMin, appRequestRefreshRateMax}};
+ {Fps(primaryRefreshRateMin), Fps(primaryRefreshRateMax)},
+ {Fps(appRequestRefreshRateMin), Fps(appRequestRefreshRateMax)}};
constexpr bool kOverridePolicy = false;
return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy);
@@ -6058,10 +6089,10 @@
mRefreshRateConfigs->getDisplayManagerPolicy();
*outDefaultConfig = policy.defaultConfig.value();
*outAllowGroupSwitching = policy.allowGroupSwitching;
- *outPrimaryRefreshRateMin = policy.primaryRange.min;
- *outPrimaryRefreshRateMax = policy.primaryRange.max;
- *outAppRequestRefreshRateMin = policy.appRequestRange.min;
- *outAppRequestRefreshRateMax = policy.appRequestRange.max;
+ *outPrimaryRefreshRateMin = policy.primaryRange.min.getValue();
+ *outPrimaryRefreshRateMax = policy.primaryRange.max.getValue();
+ *outAppRequestRefreshRateMin = policy.appRequestRange.min.getValue();
+ *outAppRequestRefreshRateMax = policy.appRequestRange.max.getValue();
return NO_ERROR;
} else if (display->isVirtual()) {
return INVALID_OPERATION;
@@ -6070,10 +6101,10 @@
*outDefaultConfig = getHwComposer().getActiveConfigIndex(displayId);
*outAllowGroupSwitching = false;
auto vsyncPeriod = getHwComposer().getActiveConfig(displayId)->getVsyncPeriod();
- *outPrimaryRefreshRateMin = 1e9f / vsyncPeriod;
- *outPrimaryRefreshRateMax = 1e9f / vsyncPeriod;
- *outAppRequestRefreshRateMin = 1e9f / vsyncPeriod;
- *outAppRequestRefreshRateMax = 1e9f / vsyncPeriod;
+ *outPrimaryRefreshRateMin = Fps::fromPeriodNsecs(vsyncPeriod).getValue();
+ *outPrimaryRefreshRateMax = Fps::fromPeriodNsecs(vsyncPeriod).getValue();
+ *outAppRequestRefreshRateMin = Fps::fromPeriodNsecs(vsyncPeriod).getValue();
+ *outAppRequestRefreshRateMax = Fps::fromPeriodNsecs(vsyncPeriod).getValue();
return NO_ERROR;
}
}
@@ -6169,7 +6200,7 @@
return BAD_VALUE;
}
if (layer->setFrameRate(
- Layer::FrameRate(frameRate,
+ Layer::FrameRate(Fps{frameRate},
Layer::FrameRate::convertCompatibility(compatibility),
shouldBeSeamless))) {
setTransactionFlags(eTraversalNeeded);
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index 576bba7..497ebd3 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -85,7 +85,7 @@
std::unique_ptr<Runner> runner;
struct Config {
- uint32_t flags = TRACE_CRITICAL | TRACE_INPUT;
+ uint32_t flags = TRACE_CRITICAL | TRACE_INPUT | TRACE_SYNC;
size_t bufferSize = DEFAULT_BUFFER_SIZE;
} mConfig;
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index ca24493..1797af4 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -153,7 +153,7 @@
}
status_t TransactionCompletedThread::finalizePendingCallbackHandles(
- const std::deque<sp<CallbackHandle>>& handles) {
+ const std::deque<sp<CallbackHandle>>& handles, const std::vector<JankData>& jankData) {
if (handles.empty()) {
return NO_ERROR;
}
@@ -186,7 +186,7 @@
ALOGW("cannot find listener in mPendingTransactions");
}
- status_t err = addCallbackHandle(handle);
+ status_t err = addCallbackHandle(handle, jankData);
if (err != NO_ERROR) {
ALOGE("could not add callback handle");
return err;
@@ -204,7 +204,7 @@
return BAD_VALUE;
}
- return addCallbackHandle(handle);
+ return addCallbackHandle(handle, std::vector<JankData>());
}
status_t TransactionCompletedThread::findTransactionStats(
@@ -225,7 +225,8 @@
return BAD_VALUE;
}
-status_t TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle) {
+status_t TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle,
+ const std::vector<JankData>& jankData) {
// If we can't find the transaction stats something has gone wrong. The client should call
// startRegistration before trying to add a callback handle.
TransactionStats* transactionStats;
@@ -246,7 +247,7 @@
handle->dequeueReadyTime);
transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTime,
handle->previousReleaseFence,
- handle->transformHint, eventStats);
+ handle->transformHint, eventStats, jankData);
}
return NO_ERROR;
}
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
index f50147a..c4ba7e4 100644
--- a/services/surfaceflinger/TransactionCompletedThread.h
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -73,7 +73,8 @@
// presented.
status_t registerPendingCallbackHandle(const sp<CallbackHandle>& handle);
// Notifies the TransactionCompletedThread that a pending CallbackHandle has been presented.
- status_t finalizePendingCallbackHandles(const std::deque<sp<CallbackHandle>>& handles);
+ status_t finalizePendingCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
+ const std::vector<JankData>& jankData);
// Adds the Transaction CallbackHandle from a layer that does not need to be relatched and
// presented this frame.
@@ -93,7 +94,8 @@
const std::vector<CallbackId>& callbackIds,
TransactionStats** outTransactionStats) REQUIRES(mMutex);
- status_t addCallbackHandle(const sp<CallbackHandle>& handle) REQUIRES(mMutex);
+ status_t addCallbackHandle(const sp<CallbackHandle>& handle,
+ const std::vector<JankData>& jankData) REQUIRES(mMutex);
class ThreadDeathRecipient : public IBinder::DeathRecipient {
public:
diff --git a/services/surfaceflinger/tests/VirtualDisplay_test.cpp b/services/surfaceflinger/tests/VirtualDisplay_test.cpp
index 9fd2227..18e0806 100644
--- a/services/surfaceflinger/tests/VirtualDisplay_test.cpp
+++ b/services/surfaceflinger/tests/VirtualDisplay_test.cpp
@@ -52,6 +52,8 @@
virtualDisplay.clear();
// Sync here to ensure the display was completely destroyed in SF
t.apply(true);
+ // add another sync since we are deferring the display destruction
+ t.apply(true);
sp<Surface> surface = new Surface(mProducer);
sp<ANativeWindow> window(surface);
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 31a5126..538b10d 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -69,6 +69,7 @@
using Transaction = SurfaceComposerClient::Transaction;
using Attribute = V2_4::IComposerClient::Attribute;
+using Display = V2_1::Display;
///////////////////////////////////////////////
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 871222c..a00e959 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -44,6 +44,7 @@
"DisplayDevice_GetBestColorModeTest.cpp",
"DisplayDevice_SetProjectionTest.cpp",
"EventThreadTest.cpp",
+ "FpsTest.cpp",
"FrameTimelineTest.cpp",
"HWComposerTest.cpp",
"OneShotTimerTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/FakeVsyncConfiguration.h b/services/surfaceflinger/tests/unittests/FakeVsyncConfiguration.h
index 4cd1e0a..36e24d2 100644
--- a/services/surfaceflinger/tests/unittests/FakeVsyncConfiguration.h
+++ b/services/surfaceflinger/tests/unittests/FakeVsyncConfiguration.h
@@ -26,7 +26,7 @@
static constexpr nsecs_t FAKE_PHASE_OFFSET_NS = 0;
static constexpr auto FAKE_DURATION_OFFSET_NS = std::chrono::nanoseconds(0);
- VsyncConfigSet getConfigsForRefreshRate(float) const override { return getCurrentConfigs(); }
+ VsyncConfigSet getConfigsForRefreshRate(Fps) const override { return getCurrentConfigs(); }
VsyncConfigSet getCurrentConfigs() const override {
return {{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS, FAKE_DURATION_OFFSET_NS,
@@ -37,7 +37,7 @@
FAKE_DURATION_OFFSET_NS}};
}
- void setRefreshRateFps(float) override {}
+ void setRefreshRateFps(Fps) override {}
void dump(std::string&) const override {}
};
diff --git a/services/surfaceflinger/tests/unittests/FpsTest.cpp b/services/surfaceflinger/tests/unittests/FpsTest.cpp
new file mode 100644
index 0000000..db732cf
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FpsTest.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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 "Fps.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+
+TEST(FpsTest, construct) {
+ Fps fpsDefault;
+ EXPECT_FALSE(fpsDefault.isValid());
+
+ Fps fps1(60.0f);
+ EXPECT_TRUE(fps1.isValid());
+ Fps fps2 = Fps::fromPeriodNsecs(static_cast<nsecs_t>(1e9f / 60.0f));
+ EXPECT_TRUE(fps2.isValid());
+ EXPECT_TRUE(fps1.equalsWithMargin(fps2));
+}
+
+TEST(FpsTest, compare) {
+ constexpr float kEpsilon = 1e-4f;
+ const Fps::EqualsInBuckets equalsInBuckets;
+ const Fps::EqualsWithMargin equalsWithMargin;
+
+ EXPECT_TRUE(Fps(60.0f).equalsWithMargin(Fps(60.f)));
+ EXPECT_TRUE(Fps(60.0f).equalsWithMargin(Fps(60.f - kEpsilon)));
+ EXPECT_TRUE(Fps(60.0f).equalsWithMargin(Fps(60.f + kEpsilon)));
+
+ EXPECT_TRUE(equalsInBuckets(Fps(60.0f), Fps(60.0f)));
+ EXPECT_TRUE(equalsInBuckets(Fps(60.0f), Fps(60.0f - kEpsilon)));
+ EXPECT_TRUE(equalsInBuckets(Fps(60.0f), Fps(60.0f + kEpsilon)));
+
+ EXPECT_TRUE(equalsWithMargin(Fps(60.0f), Fps(60.0f)));
+ EXPECT_TRUE(equalsWithMargin(Fps(60.0f), Fps(60.0f - kEpsilon)));
+ EXPECT_TRUE(equalsWithMargin(Fps(60.0f), Fps(60.0f + kEpsilon)));
+
+ EXPECT_TRUE(Fps(60.0f).lessThanOrEqualWithMargin(Fps(60.f + kEpsilon)));
+ EXPECT_TRUE(Fps(60.0f).lessThanOrEqualWithMargin(Fps(60.f)));
+ EXPECT_TRUE(Fps(60.0f).lessThanOrEqualWithMargin(Fps(60.f - kEpsilon)));
+
+ EXPECT_TRUE(Fps(60.0f).greaterThanOrEqualWithMargin(Fps(60.f + kEpsilon)));
+ EXPECT_TRUE(Fps(60.0f).greaterThanOrEqualWithMargin(Fps(60.f)));
+ EXPECT_TRUE(Fps(60.0f).greaterThanOrEqualWithMargin(Fps(60.f - kEpsilon)));
+
+ // Fps with difference of 1 should be different
+ EXPECT_FALSE(Fps(60.0f).equalsWithMargin(Fps(61.f)));
+ EXPECT_TRUE(Fps(60.0f).lessThanWithMargin(Fps(61.f)));
+ EXPECT_TRUE(Fps(60.0f).greaterThanWithMargin(Fps(59.f)));
+
+ // These are common refresh rates which should be different.
+ EXPECT_FALSE(Fps(60.0f).equalsWithMargin(Fps(59.94f)));
+ EXPECT_TRUE(Fps(60.0f).greaterThanWithMargin(Fps(59.94f)));
+ EXPECT_FALSE(equalsInBuckets(Fps(60.0f), Fps(59.94f)));
+ EXPECT_FALSE(equalsWithMargin(Fps(60.0f), Fps(59.94f)));
+ EXPECT_NE(std::hash<Fps>()(Fps(60.0f)), std::hash<Fps>()(Fps(59.94f)));
+
+ EXPECT_FALSE(Fps(30.0f).equalsWithMargin(Fps(29.97f)));
+ EXPECT_TRUE(Fps(30.0f).greaterThanWithMargin(Fps(29.97f)));
+ EXPECT_FALSE(equalsInBuckets(Fps(30.0f), Fps(29.97f)));
+ EXPECT_FALSE(equalsWithMargin(Fps(30.0f), Fps(29.97f)));
+ EXPECT_NE(std::hash<Fps>()(Fps(30.0f)), std::hash<Fps>()(Fps(29.97f)));
+}
+
+TEST(FpsTest, getIntValue) {
+ EXPECT_EQ(30, Fps(30.1f).getIntValue());
+ EXPECT_EQ(31, Fps(30.9f).getIntValue());
+ EXPECT_EQ(31, Fps(30.5f).getIntValue());
+}
+
+TEST(FpsTest, equalsInBucketsImpliesEqualHashes) {
+ constexpr float kStep = 1e-4f;
+ const Fps::EqualsInBuckets equals;
+ for (float fps = 30.0f; fps < 31.0f; fps += kStep) {
+ const Fps left(fps);
+ const Fps right(fps + kStep);
+ if (equals(left, right)) {
+ ASSERT_EQ(std::hash<Fps>()(left), std::hash<Fps>()(right))
+ << "left= " << left << " right=" << right;
+ }
+ }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 411e780..43b5afe 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -205,7 +205,7 @@
// Set up the display frame
mFrameTimeline->setSfWakeUp(token1, 20);
- mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1), SurfaceFrame::PresentState::Dropped);
+ mFrameTimeline->addSurfaceFrame(surfaceFrame1, SurfaceFrame::PresentState::Dropped);
mFrameTimeline->setSfPresent(25, presentFence1);
presentFence1->signalForTest(30);
@@ -229,11 +229,11 @@
sLayerNameOne, surfaceFrameToken1);
auto surfaceFrame2 =
mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameTwo,
- sLayerNameTwo, surfaceFrameToken1);
+ sLayerNameTwo, surfaceFrameToken2);
mFrameTimeline->setSfWakeUp(sfToken1, 22);
- mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1),
+ mFrameTimeline->addSurfaceFrame(surfaceFrame1,
SurfaceFrame::PresentState::Presented);
- mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame2),
+ mFrameTimeline->addSurfaceFrame(surfaceFrame2,
SurfaceFrame::PresentState::Presented);
mFrameTimeline->setSfPresent(26, presentFence1);
auto displayFrame = getDisplayFrame(0);
@@ -246,13 +246,16 @@
EXPECT_EQ(presentedSurfaceFrame1.getActuals().presentTime, 0);
EXPECT_EQ(presentedSurfaceFrame2.getActuals().presentTime, 0);
+ EXPECT_EQ(surfaceFrame1->getToken(), surfaceFrameToken1);
+ EXPECT_EQ(surfaceFrame2->getToken(), surfaceFrameToken2);
+
// Trigger a flush by finalizing the next DisplayFrame
auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
auto surfaceFrame3 =
mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
sLayerNameOne, surfaceFrameToken2);
mFrameTimeline->setSfWakeUp(sfToken2, 52);
- mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame3), SurfaceFrame::PresentState::Dropped);
+ mFrameTimeline->addSurfaceFrame(surfaceFrame3, SurfaceFrame::PresentState::Dropped);
mFrameTimeline->setSfPresent(56, presentFence2);
displayFrame = getDisplayFrame(0);
@@ -260,6 +263,8 @@
EXPECT_EQ(displayFrame->surfaceFlingerActuals.presentTime, 42);
EXPECT_EQ(presentedSurfaceFrame1.getActuals().presentTime, 42);
EXPECT_EQ(presentedSurfaceFrame2.getActuals().presentTime, 42);
+ EXPECT_NE(surfaceFrame1->getJankType(), std::nullopt);
+ EXPECT_NE(surfaceFrame2->getJankType(), std::nullopt);
}
TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) {
@@ -275,7 +280,7 @@
mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
sLayerNameOne, surfaceFrameToken);
mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor);
- mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
+ mFrameTimeline->addSurfaceFrame(surfaceFrame,
SurfaceFrame::PresentState::Presented);
mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence);
presentFence->signalForTest(32 + frameTimeFactor);
@@ -297,7 +302,7 @@
mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
sLayerNameOne, surfaceFrameToken);
mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor);
- mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame), SurfaceFrame::PresentState::Presented);
+ mFrameTimeline->addSurfaceFrame(surfaceFrame, SurfaceFrame::PresentState::Presented);
mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence);
presentFence->signalForTest(32 + frameTimeFactor);
displayFrame0 = getDisplayFrame(0);
@@ -337,7 +342,7 @@
sLayerNameOne, std::nullopt);
int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
mFrameTimeline->setSfWakeUp(sfToken, 22);
- mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
+ mFrameTimeline->addSurfaceFrame(surfaceFrame,
SurfaceFrame::PresentState::Presented);
mFrameTimeline->setSfPresent(27, presentFence);
}
@@ -353,7 +358,7 @@
sLayerNameOne, std::nullopt);
int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
mFrameTimeline->setSfWakeUp(sfToken, 22);
- mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
+ mFrameTimeline->addSurfaceFrame(surfaceFrame,
SurfaceFrame::PresentState::Presented);
mFrameTimeline->setSfPresent(27, presentFence);
}
@@ -369,7 +374,7 @@
sLayerNameOne, std::nullopt);
int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
mFrameTimeline->setSfWakeUp(sfToken, 22);
- mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
+ mFrameTimeline->addSurfaceFrame(surfaceFrame,
SurfaceFrame::PresentState::Presented);
mFrameTimeline->setSfPresent(27, presentFence);
}
@@ -396,10 +401,10 @@
sLayerNameOne, surfaceFrameToken1);
mFrameTimeline->setSfWakeUp(sfToken1,
std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count());
- mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1),
+ mFrameTimeline->addSurfaceFrame(surfaceFrame1,
SurfaceFrame::PresentState::Presented);
presentFence1->signalForTest(
- std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count());
+ std::chrono::duration_cast<std::chrono::nanoseconds>(70ms).count());
mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(59ms).count(),
presentFence1);
@@ -423,12 +428,14 @@
sLayerNameOne, surfaceFrameToken1);
mFrameTimeline->setSfWakeUp(sfToken1,
std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count());
- mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1),
+ mFrameTimeline->addSurfaceFrame(surfaceFrame1,
SurfaceFrame::PresentState::Presented);
presentFence1->signalForTest(
std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count());
mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(59ms).count(),
presentFence1);
+ EXPECT_NE(surfaceFrame1->getJankType(), std::nullopt);
+ EXPECT_TRUE((surfaceFrame1->getJankType().value() & JankType::Display) != 0);
}
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) {
@@ -453,12 +460,15 @@
mFrameTimeline->setSfWakeUp(sfToken1,
std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count());
- mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1),
+ mFrameTimeline->addSurfaceFrame(surfaceFrame1,
SurfaceFrame::PresentState::Presented);
presentFence1->signalForTest(
std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count());
mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(),
presentFence1);
+
+ EXPECT_NE(surfaceFrame1->getJankType(), std::nullopt);
+ EXPECT_TRUE((surfaceFrame1->getJankType().value() & JankType::AppDeadlineMissed) != 0);
}
/*
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index fbb4637..cbc1e02 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -32,7 +32,9 @@
using testing::_;
using testing::Return;
-namespace android::scheduler {
+namespace android {
+
+namespace scheduler {
class LayerHistoryTest : public testing::Test {
protected:
@@ -43,11 +45,11 @@
static constexpr auto REFRESH_RATE_AVERAGE_HISTORY_DURATION =
LayerInfo::RefreshRateHistory::HISTORY_DURATION;
- static constexpr float LO_FPS = 30.f;
- static constexpr auto LO_FPS_PERIOD = static_cast<nsecs_t>(1e9f / LO_FPS);
+ static constexpr Fps LO_FPS{30.f};
+ static constexpr auto LO_FPS_PERIOD = LO_FPS.getPeriodNsecs();
- static constexpr float HI_FPS = 90.f;
- static constexpr auto HI_FPS_PERIOD = static_cast<nsecs_t>(1e9f / HI_FPS);
+ static constexpr Fps HI_FPS{90.f};
+ static constexpr auto HI_FPS_PERIOD = HI_FPS.getPeriodNsecs();
LayerHistoryTest() { mFlinger.resetScheduler(mScheduler); }
@@ -88,20 +90,19 @@
return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger(), std::move(name)));
}
- void recordFramesAndExpect(const sp<mock::MockLayer>& layer, nsecs_t& time, float frameRate,
- float desiredRefreshRate, int numFrames) {
- const nsecs_t framePeriod = static_cast<nsecs_t>(1e9f / frameRate);
+ void recordFramesAndExpect(const sp<mock::MockLayer>& layer, nsecs_t& time, Fps frameRate,
+ Fps desiredRefreshRate, int numFrames) {
LayerHistory::Summary summary;
for (int i = 0; i < numFrames; i++) {
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
- time += framePeriod;
+ time += frameRate.getPeriodNsecs();
summary = history().summarize(time);
}
ASSERT_EQ(1, summary.size());
ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- ASSERT_FLOAT_EQ(desiredRefreshRate, summary[0].desiredRefreshRate)
+ ASSERT_TRUE(desiredRefreshRate.equalsWithMargin(summary[0].desiredRefreshRate))
<< "Frame rate is " << frameRate;
}
@@ -196,7 +197,7 @@
ASSERT_EQ(1, history().summarize(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
- EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_TRUE(LO_FPS.equalsWithMargin(history().summarize(time)[0].desiredRefreshRate));
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
}
@@ -289,7 +290,7 @@
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer, getFrameRateForLayerTree())
.WillRepeatedly(
- Return(Layer::FrameRate(73.4f, Layer::FrameRateCompatibility::Default)));
+ Return(Layer::FrameRate(Fps(73.4f), Layer::FrameRateCompatibility::Default)));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -302,7 +303,7 @@
ASSERT_EQ(1, history().summarize(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, history().summarize(time)[0].vote);
- EXPECT_FLOAT_EQ(73.4f, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate));
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
@@ -311,7 +312,7 @@
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
ASSERT_EQ(1, history().summarize(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, history().summarize(time)[0].vote);
- EXPECT_FLOAT_EQ(73.4f, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate));
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
}
@@ -321,7 +322,7 @@
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer, getFrameRateForLayerTree())
.WillRepeatedly(Return(
- Layer::FrameRate(73.4f, Layer::FrameRateCompatibility::ExactOrMultiple)));
+ Layer::FrameRate(Fps(73.4f), Layer::FrameRateCompatibility::ExactOrMultiple)));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -335,7 +336,7 @@
ASSERT_EQ(1, history().summarize(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
history().summarize(time)[0].vote);
- EXPECT_FLOAT_EQ(73.4f, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate));
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
@@ -345,7 +346,7 @@
ASSERT_EQ(1, history().summarize(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
history().summarize(time)[0].vote);
- EXPECT_FLOAT_EQ(73.4f, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate));
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
}
@@ -397,7 +398,8 @@
ASSERT_EQ(2, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Min, summary[0].vote);
ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote);
- EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate);
+ EXPECT_TRUE(HI_FPS.equalsWithMargin(history().summarize(time)[1].desiredRefreshRate));
+
EXPECT_EQ(2, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
@@ -411,7 +413,7 @@
ASSERT_EQ(1, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_FLOAT_EQ(LO_FPS, summary[0].desiredRefreshRate);
+ EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
@@ -430,7 +432,7 @@
ASSERT_EQ(2, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_FLOAT_EQ(LO_FPS, summary[0].desiredRefreshRate);
+ EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
EXPECT_EQ(LayerHistory::LayerVoteType::Max, summary[1].vote);
EXPECT_EQ(2, activeLayerCount());
EXPECT_EQ(2, frequentLayerCount(time));
@@ -440,9 +442,9 @@
summary = history().summarize(time);
ASSERT_EQ(2, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_FLOAT_EQ(LO_FPS, summary[0].desiredRefreshRate);
+ EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote);
- EXPECT_FLOAT_EQ(HI_FPS, summary[1].desiredRefreshRate);
+ EXPECT_TRUE(HI_FPS.equalsWithMargin(summary[1].desiredRefreshRate));
EXPECT_EQ(2, activeLayerCount());
EXPECT_EQ(2, frequentLayerCount(time));
@@ -452,9 +454,9 @@
ASSERT_EQ(2, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_FLOAT_EQ(LO_FPS, summary[0].desiredRefreshRate);
+ EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote);
- EXPECT_FLOAT_EQ(HI_FPS, summary[1].desiredRefreshRate);
+ EXPECT_TRUE(HI_FPS.equalsWithMargin(summary[1].desiredRefreshRate));
EXPECT_EQ(2, layerCount());
EXPECT_EQ(2, activeLayerCount());
EXPECT_EQ(2, frequentLayerCount(time));
@@ -469,7 +471,7 @@
ASSERT_EQ(1, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_FLOAT_EQ(LO_FPS, summary[0].desiredRefreshRate);
+ EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
@@ -490,7 +492,7 @@
ASSERT_EQ(1, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_FLOAT_EQ(HI_FPS, summary[0].desiredRefreshRate);
+ EXPECT_TRUE(HI_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
@@ -567,12 +569,12 @@
EXPECT_CALL(*explicitVisiblelayer, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*explicitVisiblelayer, getFrameRateForLayerTree())
.WillRepeatedly(Return(
- Layer::FrameRate(60.0f, Layer::FrameRateCompatibility::ExactOrMultiple)));
+ Layer::FrameRate(Fps(60.0f), Layer::FrameRateCompatibility::ExactOrMultiple)));
EXPECT_CALL(*explicitInvisiblelayer, isVisible()).WillRepeatedly(Return(false));
EXPECT_CALL(*explicitInvisiblelayer, getFrameRateForLayerTree())
.WillRepeatedly(Return(
- Layer::FrameRate(90.0f, Layer::FrameRateCompatibility::ExactOrMultiple)));
+ Layer::FrameRate(Fps(90.0f), Layer::FrameRateCompatibility::ExactOrMultiple)));
nsecs_t time = systemTime();
@@ -585,7 +587,7 @@
ASSERT_EQ(1, history().summarize(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
history().summarize(time)[0].vote);
- EXPECT_FLOAT_EQ(60.0f, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_TRUE(Fps(60.0f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate));
EXPECT_EQ(2, activeLayerCount());
EXPECT_EQ(2, frequentLayerCount(time));
}
@@ -643,7 +645,7 @@
nsecs_t time = systemTime();
for (float fps = 54.0f; fps < 65.0f; fps += 0.1f) {
- recordFramesAndExpect(layer, time, fps, 60.0f, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, Fps(fps), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE);
}
}
@@ -653,13 +655,13 @@
EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
nsecs_t time = systemTime();
- recordFramesAndExpect(layer, time, 60.0f, 60.0f, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, Fps(60.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 60.0f, 60.0f, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 30.0f, 60.0f, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 30.0f, 30.0f, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 60.0f, 30.0f, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 60.0f, 60.0f, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, Fps(60.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, Fps(30.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, Fps(30.0f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, Fps(60.0f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, Fps(60.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE);
}
TEST_F(LayerHistoryTest, heuristicLayerNotOscillating) {
@@ -669,11 +671,11 @@
nsecs_t time = systemTime();
- recordFramesAndExpect(layer, time, 27.10f, 30.0f, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 26.90f, 30.0f, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 26.00f, 24.0f, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 26.90f, 24.0f, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 27.10f, 30.0f, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, Fps(27.10f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, Fps(26.90f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, Fps(26.00f), Fps(24.0f), PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, Fps(26.90f), Fps(24.0f), PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, Fps(27.10f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE);
}
class LayerHistoryTestParameterized : public LayerHistoryTest,
@@ -724,7 +726,7 @@
bool max = false;
bool min = false;
- float heuristic = 0;
+ Fps heuristic{0.0};
for (const auto& layer : history().summarize(time)) {
if (layer.vote == LayerHistory::LayerVoteType::Heuristic) {
heuristic = layer.desiredRefreshRate;
@@ -736,7 +738,7 @@
}
if (infrequentLayerUpdates > FREQUENT_LAYER_WINDOW_SIZE) {
- EXPECT_FLOAT_EQ(24.0f, heuristic);
+ EXPECT_TRUE(Fps(24.0f).equalsWithMargin(heuristic));
EXPECT_FALSE(max);
if (history().summarize(time).size() == 2) {
EXPECT_TRUE(min);
@@ -750,4 +752,5 @@
::testing::Values(1s, 2s, 3s, 4s, 5s));
} // namespace
-} // namespace android::scheduler
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index f2b7191..83ad737 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -30,6 +30,7 @@
using testing::_;
namespace android {
+
namespace scheduler {
namespace hal = android::hardware::graphics::composer::hal;
@@ -43,11 +44,11 @@
RefreshRateConfigsTest();
~RefreshRateConfigsTest();
- float findClosestKnownFrameRate(const RefreshRateConfigs& refreshRateConfigs, float frameRate) {
+ Fps findClosestKnownFrameRate(const RefreshRateConfigs& refreshRateConfigs, Fps frameRate) {
return refreshRateConfigs.findClosestKnownFrameRate(frameRate);
}
- std::vector<float> getKnownFrameRate(const RefreshRateConfigs& refreshRateConfigs) {
+ std::vector<Fps> getKnownFrameRate(const RefreshRateConfigs& refreshRateConfigs) {
return refreshRateConfigs.mKnownFrameRates;
}
@@ -62,29 +63,29 @@
// Test configs
std::shared_ptr<const HWC2::Display::Config> mConfig60 =
- createConfig(HWC_CONFIG_ID_60, 0, static_cast<int64_t>(1e9f / 60));
+ createConfig(HWC_CONFIG_ID_60, 0, Fps(60.0f).getPeriodNsecs());
std::shared_ptr<const HWC2::Display::Config> mConfig90 =
- createConfig(HWC_CONFIG_ID_90, 0, static_cast<int64_t>(1e9f / 90));
+ createConfig(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs());
std::shared_ptr<const HWC2::Display::Config> mConfig90DifferentGroup =
- createConfig(HWC_CONFIG_ID_90, 1, static_cast<int64_t>(1e9f / 90));
+ createConfig(HWC_CONFIG_ID_90, 1, Fps(90.0f).getPeriodNsecs());
std::shared_ptr<const HWC2::Display::Config> mConfig90DifferentResolution =
- createConfig(HWC_CONFIG_ID_90, 0, static_cast<int64_t>(1e9f / 90), 111, 222);
+ createConfig(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs(), 111, 222);
std::shared_ptr<const HWC2::Display::Config> mConfig72 =
- createConfig(HWC_CONFIG_ID_72, 0, static_cast<int64_t>(1e9f / 72));
+ createConfig(HWC_CONFIG_ID_72, 0, Fps(72.0f).getPeriodNsecs());
std::shared_ptr<const HWC2::Display::Config> mConfig72DifferentGroup =
- createConfig(HWC_CONFIG_ID_72, 1, static_cast<int64_t>(1e9f / 72));
+ createConfig(HWC_CONFIG_ID_72, 1, Fps(72.0f).getPeriodNsecs());
std::shared_ptr<const HWC2::Display::Config> mConfig120 =
- createConfig(HWC_CONFIG_ID_120, 0, static_cast<int64_t>(1e9f / 120));
+ createConfig(HWC_CONFIG_ID_120, 0, Fps(120.0f).getPeriodNsecs());
std::shared_ptr<const HWC2::Display::Config> mConfig120DifferentGroup =
- createConfig(HWC_CONFIG_ID_120, 1, static_cast<int64_t>(1e9f / 120));
+ createConfig(HWC_CONFIG_ID_120, 1, Fps(120.0f).getPeriodNsecs());
std::shared_ptr<const HWC2::Display::Config> mConfig30 =
- createConfig(HWC_CONFIG_ID_30, 0, static_cast<int64_t>(1e9f / 30));
+ createConfig(HWC_CONFIG_ID_30, 0, Fps(30.0f).getPeriodNsecs());
std::shared_ptr<const HWC2::Display::Config> mConfig30DifferentGroup =
- createConfig(HWC_CONFIG_ID_30, 1, static_cast<int64_t>(1e9f / 30));
+ createConfig(HWC_CONFIG_ID_30, 1, Fps(30.0f).getPeriodNsecs());
std::shared_ptr<const HWC2::Display::Config> mConfig25DifferentGroup =
- createConfig(HWC_CONFIG_ID_25, 1, static_cast<int64_t>(1e9f / 25));
+ createConfig(HWC_CONFIG_ID_25, 1, Fps(25.0f).getPeriodNsecs());
std::shared_ptr<const HWC2::Display::Config> mConfig50 =
- createConfig(HWC_CONFIG_ID_50, 0, static_cast<int64_t>(1e9f / 50));
+ createConfig(HWC_CONFIG_ID_50, 0, Fps(50.0f).getPeriodNsecs());
// Test device configurations
// The positions of the configs in the arrays below MUST match their IDs. For example,
@@ -124,23 +125,23 @@
mConfig50};
// Expected RefreshRate objects
- RefreshRate mExpected60Config = {HWC_CONFIG_ID_60, mConfig60, "60fps", 60,
+ RefreshRate mExpected60Config = {HWC_CONFIG_ID_60, mConfig60, Fps(60),
RefreshRate::ConstructorTag(0)};
RefreshRate mExpectedAlmost60Config = {HWC_CONFIG_ID_60,
- createConfig(HWC_CONFIG_ID_60, 0, 16666665), "60fps", 60,
+ createConfig(HWC_CONFIG_ID_60, 0, 16666665), Fps(60),
RefreshRate::ConstructorTag(0)};
- RefreshRate mExpected90Config = {HWC_CONFIG_ID_90, mConfig90, "90fps", 90,
+ RefreshRate mExpected90Config = {HWC_CONFIG_ID_90, mConfig90, Fps(90),
RefreshRate::ConstructorTag(0)};
RefreshRate mExpected90DifferentGroupConfig = {HWC_CONFIG_ID_90, mConfig90DifferentGroup,
- "90fps", 90, RefreshRate::ConstructorTag(0)};
+ Fps(90), RefreshRate::ConstructorTag(0)};
RefreshRate mExpected90DifferentResolutionConfig = {HWC_CONFIG_ID_90,
- mConfig90DifferentResolution, "90fps", 90,
+ mConfig90DifferentResolution, Fps(90),
RefreshRate::ConstructorTag(0)};
- RefreshRate mExpected72Config = {HWC_CONFIG_ID_72, mConfig72, "72fps", 72,
+ RefreshRate mExpected72Config = {HWC_CONFIG_ID_72, mConfig72, Fps(72.0f),
RefreshRate::ConstructorTag(0)};
- RefreshRate mExpected30Config = {HWC_CONFIG_ID_30, mConfig30, "30fps", 30,
+ RefreshRate mExpected30Config = {HWC_CONFIG_ID_30, mConfig30, Fps(30),
RefreshRate::ConstructorTag(0)};
- RefreshRate mExpected120Config = {HWC_CONFIG_ID_120, mConfig120, "120fps", 120,
+ RefreshRate mExpected120Config = {HWC_CONFIG_ID_120, mConfig120, Fps(120),
RefreshRate::ConstructorTag(0)};
Hwc2::mock::Display mDisplay;
@@ -192,8 +193,11 @@
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m60OnlyConfigDevice,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HwcConfigIndexType(10), {60, 60}}), 0);
- ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {20, 40}}), 0);
+ ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy(
+ {HwcConfigIndexType(10), {Fps(60), Fps(60)}}),
+ 0);
+ ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(20), Fps(40)}}),
+ 0);
}
TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) {
@@ -227,7 +231,8 @@
ASSERT_EQ(mExpected60Config, minRate60);
ASSERT_EQ(mExpected60Config, performanceRate60);
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60, 90}}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(60), Fps(90)}}),
+ 0);
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
@@ -252,7 +257,8 @@
ASSERT_EQ(mExpected60Config, minRate60);
ASSERT_EQ(mExpected60Config, performanceRate60);
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60, 90}}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(60), Fps(90)}}),
+ 0);
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
@@ -274,7 +280,8 @@
ASSERT_EQ(mExpected60Config, minRate);
ASSERT_EQ(mExpected90Config, performanceRate);
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}),
+ 0);
auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
@@ -297,7 +304,8 @@
EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90);
}
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(90), Fps(90)}}),
+ 0);
{
auto& current = refreshRateConfigs->getCurrentRefreshRate();
EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90);
@@ -315,7 +323,8 @@
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}),
+ 0);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
}
@@ -338,34 +347,35 @@
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 90.0f;
+ lr.desiredRefreshRate = Fps(90.0f);
lr.vote = LayerVoteType::Heuristic;
lr.name = "90Hz Heuristic";
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 60.0f;
+ lr.desiredRefreshRate = Fps(60.0f);
lr.name = "60Hz Heuristic";
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 45.0f;
+ lr.desiredRefreshRate = Fps(45.0f);
lr.name = "45Hz Heuristic";
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 30.0f;
+ lr.desiredRefreshRate = Fps(30.0f);
lr.name = "30Hz Heuristic";
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 24.0f;
+ lr.desiredRefreshRate = Fps(24.0f);
lr.name = "24Hz Heuristic";
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
lr.name = "";
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}),
+ 0);
lr.vote = LayerVoteType::Min;
EXPECT_EQ(mExpected60Config,
@@ -375,28 +385,30 @@
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 90.0f;
+ lr.desiredRefreshRate = Fps(90.0f);
lr.vote = LayerVoteType::Heuristic;
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 60.0f;
+ lr.desiredRefreshRate = Fps(60.0f);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 45.0f;
+ lr.desiredRefreshRate = Fps(45.0f);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 30.0f;
+ lr.desiredRefreshRate = Fps(30.0f);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 24.0f;
+ lr.desiredRefreshRate = Fps(24.0f);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+ {HWC_CONFIG_ID_90, {Fps(90.0f), Fps(90.0f)}}),
+ 0);
lr.vote = LayerVoteType::Min;
EXPECT_EQ(mExpected90Config,
@@ -406,28 +418,30 @@
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 90.0f;
+ lr.desiredRefreshRate = Fps(90.0f);
lr.vote = LayerVoteType::Heuristic;
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 60.0f;
+ lr.desiredRefreshRate = Fps(60.0f);
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 45.0f;
+ lr.desiredRefreshRate = Fps(45.0f);
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 30.0f;
+ lr.desiredRefreshRate = Fps(30.0f);
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 24.0f;
+ lr.desiredRefreshRate = Fps(24.0f);
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0, 120}}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+ {HWC_CONFIG_ID_60, {Fps(0.0f), Fps(120.0f)}}),
+ 0);
lr.vote = LayerVoteType::Min;
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
@@ -436,24 +450,24 @@
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 90.0f;
+ lr.desiredRefreshRate = Fps(90.0f);
lr.vote = LayerVoteType::Heuristic;
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 60.0f;
+ lr.desiredRefreshRate = Fps(60.0f);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 45.0f;
+ lr.desiredRefreshRate = Fps(45.0f);
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 30.0f;
+ lr.desiredRefreshRate = Fps(30.0f);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 24.0f;
+ lr.desiredRefreshRate = Fps(24.0f);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
}
@@ -474,24 +488,24 @@
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 90.0f;
+ lr.desiredRefreshRate = Fps(90.0f);
lr.vote = LayerVoteType::Heuristic;
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 60.0f;
+ lr.desiredRefreshRate = Fps(60.0f);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 45.0f;
+ lr.desiredRefreshRate = Fps(45.0f);
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 30.0f;
+ lr.desiredRefreshRate = Fps(30.0f);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 24.0f;
+ lr.desiredRefreshRate = Fps(24.0f);
EXPECT_EQ(mExpected72Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
}
@@ -506,23 +520,23 @@
auto& lr1 = layers[0];
auto& lr2 = layers[1];
- lr1.desiredRefreshRate = 24.0f;
+ lr1.desiredRefreshRate = Fps(24.0f);
lr1.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = 60.0f;
+ lr2.desiredRefreshRate = Fps(60.0f);
lr2.vote = LayerVoteType::Heuristic;
EXPECT_EQ(mExpected120Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr1.desiredRefreshRate = 24.0f;
+ lr1.desiredRefreshRate = Fps(24.0f);
lr1.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = 48.0f;
+ lr2.desiredRefreshRate = Fps(48.0f);
lr2.vote = LayerVoteType::Heuristic;
EXPECT_EQ(mExpected72Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr1.desiredRefreshRate = 24.0f;
+ lr1.desiredRefreshRate = Fps(24.0f);
lr1.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = 48.0f;
+ lr2.desiredRefreshRate = Fps(48.0f);
lr2.vote = LayerVoteType::Heuristic;
EXPECT_EQ(mExpected72Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
@@ -538,82 +552,82 @@
auto& lr1 = layers[0];
auto& lr2 = layers[1];
- lr1.desiredRefreshRate = 24.0f;
+ lr1.desiredRefreshRate = Fps(24.0f);
lr1.vote = LayerVoteType::ExplicitDefault;
lr1.name = "24Hz ExplicitDefault";
- lr2.desiredRefreshRate = 60.0f;
+ lr2.desiredRefreshRate = Fps(60.0f);
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "60Hz Heuristic";
EXPECT_EQ(mExpected120Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr1.desiredRefreshRate = 24.0f;
+ lr1.desiredRefreshRate = Fps(24.0f);
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.name = "24Hz ExplicitExactOrMultiple";
- lr2.desiredRefreshRate = 60.0f;
+ lr2.desiredRefreshRate = Fps(60.0f);
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "60Hz Heuristic";
EXPECT_EQ(mExpected120Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr1.desiredRefreshRate = 24.0f;
+ lr1.desiredRefreshRate = Fps(24.0f);
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.name = "24Hz ExplicitExactOrMultiple";
- lr2.desiredRefreshRate = 60.0f;
+ lr2.desiredRefreshRate = Fps(60.0f);
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "60Hz ExplicitDefault";
EXPECT_EQ(mExpected120Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr1.desiredRefreshRate = 24.0f;
+ lr1.desiredRefreshRate = Fps(24.0f);
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.name = "24Hz ExplicitExactOrMultiple";
- lr2.desiredRefreshRate = 90.0f;
+ lr2.desiredRefreshRate = Fps(90.0f);
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "90Hz Heuristic";
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr1.desiredRefreshRate = 24.0f;
+ lr1.desiredRefreshRate = Fps(24.0f);
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.name = "24Hz ExplicitExactOrMultiple";
- lr2.desiredRefreshRate = 90.0f;
+ lr2.desiredRefreshRate = Fps(90.0f);
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz Heuristic";
EXPECT_EQ(mExpected72Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr1.desiredRefreshRate = 24.0f;
+ lr1.desiredRefreshRate = Fps(24.0f);
lr1.vote = LayerVoteType::ExplicitDefault;
lr1.name = "24Hz ExplicitDefault";
- lr2.desiredRefreshRate = 90.0f;
+ lr2.desiredRefreshRate = Fps(90.0f);
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "90Hz Heuristic";
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr1.desiredRefreshRate = 24.0f;
+ lr1.desiredRefreshRate = Fps(24.0f);
lr1.vote = LayerVoteType::Heuristic;
lr1.name = "24Hz Heuristic";
- lr2.desiredRefreshRate = 90.0f;
+ lr2.desiredRefreshRate = Fps(90.0f);
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz ExplicitDefault";
EXPECT_EQ(mExpected72Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr1.desiredRefreshRate = 24.0f;
+ lr1.desiredRefreshRate = Fps(24.0f);
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.name = "24Hz ExplicitExactOrMultiple";
- lr2.desiredRefreshRate = 90.0f;
+ lr2.desiredRefreshRate = Fps(90.0f);
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz ExplicitDefault";
EXPECT_EQ(mExpected72Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr1.desiredRefreshRate = 24.0f;
+ lr1.desiredRefreshRate = Fps(24.0f);
lr1.vote = LayerVoteType::ExplicitDefault;
lr1.name = "24Hz ExplicitDefault";
- lr2.desiredRefreshRate = 90.0f;
+ lr2.desiredRefreshRate = Fps(90.0f);
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.name = "90Hz ExplicitExactOrMultiple";
EXPECT_EQ(mExpected90Config,
@@ -636,24 +650,24 @@
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 90.0f;
+ lr.desiredRefreshRate = Fps(90.0f);
lr.vote = LayerVoteType::Heuristic;
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 60.0f;
+ lr.desiredRefreshRate = Fps(60.0f);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 45.0f;
+ lr.desiredRefreshRate = Fps(45.0f);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 30.0f;
+ lr.desiredRefreshRate = Fps(30.0f);
EXPECT_EQ(mExpected30Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 24.0f;
+ lr.desiredRefreshRate = Fps(24.0f);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
}
@@ -676,41 +690,41 @@
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 90.0f;
+ lr.desiredRefreshRate = Fps(90.0f);
lr.vote = LayerVoteType::Heuristic;
lr.name = "90Hz Heuristic";
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- lr.desiredRefreshRate = 60.0f;
+ lr.desiredRefreshRate = Fps(60.0f);
lr.name = "60Hz Heuristic";
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
- lr.desiredRefreshRate = 45.0f;
+ lr.desiredRefreshRate = Fps(45.0f);
lr.name = "45Hz Heuristic";
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
- lr.desiredRefreshRate = 30.0f;
+ lr.desiredRefreshRate = Fps(30.0f);
lr.name = "30Hz Heuristic";
EXPECT_EQ(mExpected30Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
- lr.desiredRefreshRate = 24.0f;
+ lr.desiredRefreshRate = Fps(24.0f);
lr.name = "24Hz Heuristic";
EXPECT_EQ(mExpected72Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
- lr.desiredRefreshRate = 24.0f;
+ lr.desiredRefreshRate = Fps(24.0f);
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
lr.name = "24Hz ExplicitExactOrMultiple";
EXPECT_EQ(mExpected72Config,
@@ -736,39 +750,39 @@
lr1.vote = LayerVoteType::Min;
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = 24.0f;
+ lr2.desiredRefreshRate = Fps(24.0f);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
lr1.vote = LayerVoteType::Min;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr2.desiredRefreshRate = 24.0f;
+ lr2.desiredRefreshRate = Fps(24.0f);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
lr1.vote = LayerVoteType::Max;
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = 60.0f;
+ lr2.desiredRefreshRate = Fps(60.0f);
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
lr1.vote = LayerVoteType::Max;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr2.desiredRefreshRate = 60.0f;
+ lr2.desiredRefreshRate = Fps(60.0f);
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
lr1.vote = LayerVoteType::Heuristic;
- lr1.desiredRefreshRate = 15.0f;
+ lr1.desiredRefreshRate = Fps(15.0f);
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = 45.0f;
+ lr2.desiredRefreshRate = Fps(45.0f);
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
lr1.vote = LayerVoteType::Heuristic;
- lr1.desiredRefreshRate = 30.0f;
+ lr1.desiredRefreshRate = Fps(30.0f);
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr2.desiredRefreshRate = 45.0f;
+ lr2.desiredRefreshRate = Fps(45.0f);
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
}
@@ -783,7 +797,7 @@
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) {
- lr.desiredRefreshRate = fps;
+ lr.desiredRefreshRate = Fps(fps);
const auto& refreshRate =
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
EXPECT_EQ(mExpected60Config, refreshRate) << fps << "Hz chooses " << refreshRate.getName();
@@ -801,33 +815,33 @@
auto& lr2 = layers[1];
lr1.vote = LayerVoteType::Heuristic;
- lr1.desiredRefreshRate = 60.0f;
+ lr1.desiredRefreshRate = Fps(60.0f);
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr2.desiredRefreshRate = 90.0f;
+ lr2.desiredRefreshRate = Fps(90.0f);
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
lr1.vote = LayerVoteType::ExplicitDefault;
- lr1.desiredRefreshRate = 90.0f;
+ lr1.desiredRefreshRate = Fps(90.0f);
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr2.desiredRefreshRate = 60.0f;
+ lr2.desiredRefreshRate = Fps(60.0f);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
lr1.vote = LayerVoteType::Heuristic;
- lr1.desiredRefreshRate = 90.0f;
+ lr1.desiredRefreshRate = Fps(90.0f);
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr2.desiredRefreshRate = 60.0f;
+ lr2.desiredRefreshRate = Fps(60.0f);
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
}
TEST_F(RefreshRateConfigsTest, testInPolicy) {
- ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(60.000004f, 60.000004f));
- ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(59.0f, 60.1f));
- ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(75.0f, 90.0f));
- ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(60.0011f, 90.0f));
- ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(50.0f, 59.998f));
+ ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(Fps(60.000004f), Fps(60.000004f)));
+ ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(Fps(59.0f), Fps(60.1f)));
+ ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(Fps(75.0f), Fps(90.0f)));
+ ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(Fps(60.0011f), Fps(90.0f)));
+ ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(Fps(50.0f), Fps(59.998f)));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_75HzContent) {
@@ -840,7 +854,7 @@
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) {
- lr.desiredRefreshRate = fps;
+ lr.desiredRefreshRate = Fps(fps);
const auto& refreshRate =
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
EXPECT_EQ(mExpected90Config, refreshRate) << fps << "Hz chooses " << refreshRate.getName();
@@ -858,25 +872,25 @@
auto& lr2 = layers[1];
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = 60.0f;
+ lr1.desiredRefreshRate = Fps(60.0f);
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = 90.0f;
+ lr2.desiredRefreshRate = Fps(90.0f);
lr2.name = "90Hz Heuristic";
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = 60.0f;
+ lr1.desiredRefreshRate = Fps(60.0f);
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::ExplicitDefault;
- lr2.desiredRefreshRate = 90.0f;
+ lr2.desiredRefreshRate = Fps(90.0f);
lr2.name = "90Hz ExplicitDefault";
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = 60.0f;
+ lr1.desiredRefreshRate = Fps(60.0f);
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
@@ -884,16 +898,16 @@
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = 30.0f;
+ lr1.desiredRefreshRate = Fps(30.0f);
lr1.name = "30Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = 90.0f;
+ lr2.desiredRefreshRate = Fps(90.0f);
lr2.name = "90Hz Heuristic";
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = 30.0f;
+ lr1.desiredRefreshRate = Fps(30.0f);
lr1.name = "30Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
@@ -912,7 +926,7 @@
auto& lr2 = layers[1];
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = 60.0f;
+ lr1.desiredRefreshRate = Fps(60.0f);
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::NoVote;
lr2.name = "NoVote";
@@ -920,7 +934,7 @@
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = 60.0f;
+ lr1.desiredRefreshRate = Fps(60.0f);
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::NoVote;
lr2.name = "NoVote";
@@ -928,7 +942,7 @@
refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = 60.0f;
+ lr1.desiredRefreshRate = Fps(60.0f);
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
@@ -936,7 +950,7 @@
refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = 60.0f;
+ lr1.desiredRefreshRate = Fps(60.0f);
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
@@ -945,10 +959,10 @@
// The other layer starts to provide buffers
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = 60.0f;
+ lr1.desiredRefreshRate = Fps(60.0f);
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = 90.0f;
+ lr2.desiredRefreshRate = Fps(90.0f);
lr2.name = "90Hz Heuristic";
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
@@ -972,40 +986,40 @@
auto& lr2 = layers[1];
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = 60.0f;
+ lr1.desiredRefreshRate = Fps(60.0f);
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = 60.0f;
+ lr2.desiredRefreshRate = Fps(60.0f);
lr2.name = "60Hz Heuristic";
refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
&consideredSignals);
EXPECT_EQ(true, consideredSignals.touch);
lr1.vote = LayerVoteType::ExplicitDefault;
- lr1.desiredRefreshRate = 60.0f;
+ lr1.desiredRefreshRate = Fps(60.0f);
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = 60.0f;
+ lr2.desiredRefreshRate = Fps(60.0f);
lr2.name = "60Hz Heuristic";
refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
&consideredSignals);
EXPECT_EQ(false, consideredSignals.touch);
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = 60.0f;
+ lr1.desiredRefreshRate = Fps(60.0f);
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = 60.0f;
+ lr2.desiredRefreshRate = Fps(60.0f);
lr2.name = "60Hz Heuristic";
refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
&consideredSignals);
EXPECT_EQ(true, consideredSignals.touch);
lr1.vote = LayerVoteType::ExplicitDefault;
- lr1.desiredRefreshRate = 60.0f;
+ lr1.desiredRefreshRate = Fps(60.0f);
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = 60.0f;
+ lr2.desiredRefreshRate = Fps(60.0f);
lr2.name = "60Hz Heuristic";
refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
&consideredSignals);
@@ -1041,7 +1055,7 @@
for (const auto& test : testCases) {
lr.vote = LayerVoteType::ExplicitDefault;
- lr.desiredRefreshRate = test.first;
+ lr.desiredRefreshRate = Fps(test.first);
std::stringstream ss;
ss << "ExplicitDefault " << test.first << " fps";
@@ -1049,7 +1063,7 @@
const auto& refreshRate =
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
- EXPECT_FLOAT_EQ(refreshRate.getFps(), test.second)
+ EXPECT_TRUE(refreshRate.getFps().equalsWithMargin(Fps(test.second)))
<< "Expecting " << test.first << "fps => " << test.second << "Hz";
}
}
@@ -1061,7 +1075,7 @@
/*currentConfigId=*/HWC_CONFIG_ID_90);
ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
- {HWC_CONFIG_ID_90, {90.f, 90.f}, {60.f, 90.f}}),
+ {HWC_CONFIG_ID_90, {Fps(90.f), Fps(90.f)}, {Fps(60.f), Fps(90.f)}}),
0);
auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
@@ -1069,7 +1083,7 @@
RefreshRateConfigs::GlobalSignals consideredSignals;
lr.vote = LayerVoteType::ExplicitDefault;
- lr.desiredRefreshRate = 60.0f;
+ lr.desiredRefreshRate = Fps(60.0f);
lr.name = "60Hz ExplicitDefault";
lr.focused = true;
EXPECT_EQ(mExpected60Config,
@@ -1085,14 +1099,14 @@
/*currentConfigId=*/HWC_CONFIG_ID_60);
ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
- {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 90.f}}),
+ {HWC_CONFIG_ID_60, {Fps(60.f), Fps(60.f)}, {Fps(60.f), Fps(90.f)}}),
0);
auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
auto& lr = layers[0];
lr.vote = LayerVoteType::ExplicitDefault;
- lr.desiredRefreshRate = 90.0f;
+ lr.desiredRefreshRate = Fps(90.0f);
lr.name = "90Hz ExplicitDefault";
lr.focused = true;
EXPECT_EQ(mExpected90Config,
@@ -1106,7 +1120,7 @@
/*currentConfigId=*/HWC_CONFIG_ID_90);
ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
- {HWC_CONFIG_ID_90, {90.f, 90.f}, {60.f, 90.f}}),
+ {HWC_CONFIG_ID_90, {Fps(90.f), Fps(90.f)}, {Fps(60.f), Fps(90.f)}}),
0);
RefreshRateConfigs::GlobalSignals consideredSignals;
@@ -1119,7 +1133,7 @@
auto& lr = layers[0];
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr.desiredRefreshRate = 60.0f;
+ lr.desiredRefreshRate = Fps(60.0f);
lr.name = "60Hz ExplicitExactOrMultiple";
lr.focused = false;
EXPECT_EQ(mExpected90Config,
@@ -1130,7 +1144,7 @@
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
lr.vote = LayerVoteType::ExplicitDefault;
- lr.desiredRefreshRate = 60.0f;
+ lr.desiredRefreshRate = Fps(60.0f);
lr.name = "60Hz ExplicitDefault";
lr.focused = false;
EXPECT_EQ(mExpected90Config,
@@ -1141,7 +1155,7 @@
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
lr.vote = LayerVoteType::Heuristic;
- lr.desiredRefreshRate = 60.0f;
+ lr.desiredRefreshRate = Fps(60.0f);
lr.name = "60Hz Heuristic";
lr.focused = false;
EXPECT_EQ(mExpected90Config,
@@ -1152,7 +1166,7 @@
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
lr.vote = LayerVoteType::Max;
- lr.desiredRefreshRate = 60.0f;
+ lr.desiredRefreshRate = Fps(60.0f);
lr.name = "60Hz Max";
lr.focused = false;
EXPECT_EQ(mExpected90Config,
@@ -1163,7 +1177,7 @@
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
lr.vote = LayerVoteType::Min;
- lr.desiredRefreshRate = 60.0f;
+ lr.desiredRefreshRate = Fps(60.0f);
lr.name = "60Hz Min";
lr.focused = false;
EXPECT_EQ(mExpected90Config,
@@ -1182,7 +1196,7 @@
auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
auto& layer = layers[0];
layer.vote = LayerVoteType::ExplicitDefault;
- layer.desiredRefreshRate = 90.0f;
+ layer.desiredRefreshRate = Fps(90.0f);
layer.seamlessness = Seamlessness::SeamedAndSeamless;
layer.name = "90Hz ExplicitDefault";
layer.focused = true;
@@ -1207,7 +1221,7 @@
// Verify that we won't do a seamless switch if we request the same mode as the default
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
- layer.desiredRefreshRate = 60.0f;
+ layer.desiredRefreshRate = Fps(60.0f);
layer.name = "60Hz ExplicitDefault";
layer.seamlessness = Seamlessness::OnlySeamless;
ASSERT_EQ(HWC_CONFIG_ID_90,
@@ -1216,7 +1230,7 @@
// Verify that if the current config is in another group and there are no layers with
// seamlessness=SeamedAndSeamless we'll go back to the default group.
- layer.desiredRefreshRate = 60.0f;
+ layer.desiredRefreshRate = Fps(60.0f);
layer.name = "60Hz ExplicitDefault";
layer.seamlessness = Seamlessness::Default;
ASSERT_EQ(HWC_CONFIG_ID_60,
@@ -1231,7 +1245,7 @@
layers.push_back(LayerRequirement{.weight = 0.5f});
auto& layer2 = layers[layers.size() - 1];
layer2.vote = LayerVoteType::ExplicitDefault;
- layer2.desiredRefreshRate = 90.0f;
+ layer2.desiredRefreshRate = Fps(90.0f);
layer2.name = "90Hz ExplicitDefault";
layer2.seamlessness = Seamlessness::SeamedAndSeamless;
layer2.focused = false;
@@ -1262,7 +1276,7 @@
auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
auto& layer = layers[0];
layer.vote = LayerVoteType::ExplicitExactOrMultiple;
- layer.desiredRefreshRate = 60.0f;
+ layer.desiredRefreshRate = Fps(60.0f);
layer.seamlessness = Seamlessness::SeamedAndSeamless;
layer.name = "60Hz ExplicitExactOrMultiple";
layer.focused = true;
@@ -1291,13 +1305,13 @@
auto layers = std::vector<
LayerRequirement>{LayerRequirement{.name = "60Hz ExplicitDefault",
.vote = LayerVoteType::ExplicitDefault,
- .desiredRefreshRate = 60.0f,
+ .desiredRefreshRate = Fps(60.0f),
.seamlessness = Seamlessness::SeamedAndSeamless,
.weight = 0.5f,
.focused = false},
LayerRequirement{.name = "25Hz ExplicitExactOrMultiple",
.vote = LayerVoteType::ExplicitExactOrMultiple,
- .desiredRefreshRate = 25.0f,
+ .desiredRefreshRate = Fps(25.0f),
.seamlessness = Seamlessness::OnlySeamless,
.weight = 1.0f,
.focused = true}};
@@ -1307,7 +1321,7 @@
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
.getConfigId());
- seamedLayer.name = "30Hz ExplicitDefault", seamedLayer.desiredRefreshRate = 30.0f;
+ seamedLayer.name = "30Hz ExplicitDefault", seamedLayer.desiredRefreshRate = Fps(30.0f);
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_30);
ASSERT_EQ(HWC_CONFIG_ID_25,
@@ -1325,7 +1339,7 @@
// Return the config ID from calling getBestRefreshRate() for a single layer with the
// given voteType and fps.
- auto getFrameRate = [&](LayerVoteType voteType, float fps, bool touchActive = false,
+ auto getFrameRate = [&](LayerVoteType voteType, Fps fps, bool touchActive = false,
bool focused = true) -> HwcConfigIndexType {
layers[0].vote = voteType;
layers[0].desiredRefreshRate = fps;
@@ -1335,43 +1349,44 @@
};
ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
- {HWC_CONFIG_ID_60, {30.f, 60.f}, {30.f, 90.f}}),
+ {HWC_CONFIG_ID_60, {Fps(30.f), Fps(60.f)}, {Fps(30.f), Fps(90.f)}}),
0);
EXPECT_EQ(HWC_CONFIG_ID_60,
refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = false})
.getConfigId());
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90.f));
- EXPECT_EQ(HWC_CONFIG_ID_30, getFrameRate(LayerVoteType::Min, 90.f));
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f));
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90.f));
- EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f));
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, Fps(90.f)));
+ EXPECT_EQ(HWC_CONFIG_ID_30, getFrameRate(LayerVoteType::Min, Fps(90.f)));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, Fps(90.f)));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, Fps(90.f)));
+ EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, Fps(90.f)));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, Fps(90.f)));
// Layers not focused are not allowed to override primary config
EXPECT_EQ(HWC_CONFIG_ID_60,
- getFrameRate(LayerVoteType::ExplicitDefault, 90.f, /*touch=*/false,
+ getFrameRate(LayerVoteType::ExplicitDefault, Fps(90.f), /*touch=*/false,
/*focused=*/false));
EXPECT_EQ(HWC_CONFIG_ID_60,
- getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f, /*touch=*/false,
+ getFrameRate(LayerVoteType::ExplicitExactOrMultiple, Fps(90.f), /*touch=*/false,
/*focused=*/false));
// Touch boost should be restricted to the primary range.
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f, /*touch=*/true));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, Fps(90.f), /*touch=*/true));
// When we're higher than the primary range max due to a layer frame rate setting, touch boost
// shouldn't drag us back down to the primary range max.
- EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f, /*touch=*/true));
+ EXPECT_EQ(HWC_CONFIG_ID_90,
+ getFrameRate(LayerVoteType::ExplicitDefault, Fps(90.f), /*touch=*/true));
EXPECT_EQ(HWC_CONFIG_ID_60,
- getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f, /*touch=*/true));
+ getFrameRate(LayerVoteType::ExplicitExactOrMultiple, Fps(90.f), /*touch=*/true));
ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
- {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 60.f}}),
+ {HWC_CONFIG_ID_60, {Fps(60.f), Fps(60.f)}, {Fps(60.f), Fps(60.f)}}),
0);
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90.f));
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, 90.f));
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f));
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90.f));
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitDefault, 90.f));
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, Fps(90.f)));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, Fps(90.f)));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, Fps(90.f)));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, Fps(90.f)));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitDefault, Fps(90.f)));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, Fps(90.f)));
}
TEST_F(RefreshRateConfigsTest, idle) {
@@ -1385,7 +1400,7 @@
const auto getIdleFrameRate = [&](LayerVoteType voteType,
bool touchActive) -> HwcConfigIndexType {
layers[0].vote = voteType;
- layers[0].desiredRefreshRate = 90.f;
+ layers[0].desiredRefreshRate = Fps(90.f);
RefreshRateConfigs::GlobalSignals consideredSignals;
const auto configId =
refreshRateConfigs
@@ -1398,7 +1413,7 @@
};
ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
- {HWC_CONFIG_ID_60, {60.f, 90.f}, {60.f, 90.f}}),
+ {HWC_CONFIG_ID_60, {Fps(60.f), Fps(90.f)}, {Fps(60.f), Fps(90.f)}}),
0);
// Idle should be lower priority than touch boost.
@@ -1439,22 +1454,22 @@
/*currentConfigId=*/HWC_CONFIG_ID_60);
for (float fps = 1.0f; fps <= 120.0f; fps += 0.1f) {
- const auto knownFrameRate = findClosestKnownFrameRate(*refreshRateConfigs, fps);
- float expectedFrameRate;
+ const auto knownFrameRate = findClosestKnownFrameRate(*refreshRateConfigs, Fps(fps));
+ Fps expectedFrameRate;
if (fps < 26.91f) {
- expectedFrameRate = 24.0f;
+ expectedFrameRate = Fps(24.0f);
} else if (fps < 37.51f) {
- expectedFrameRate = 30.0f;
+ expectedFrameRate = Fps(30.0f);
} else if (fps < 52.51f) {
- expectedFrameRate = 45.0f;
+ expectedFrameRate = Fps(45.0f);
} else if (fps < 66.01f) {
- expectedFrameRate = 60.0f;
+ expectedFrameRate = Fps(60.0f);
} else if (fps < 81.01f) {
- expectedFrameRate = 72.0f;
+ expectedFrameRate = Fps(72.0f);
} else {
- expectedFrameRate = 90.0f;
+ expectedFrameRate = Fps(90.0f);
}
- EXPECT_FLOAT_EQ(expectedFrameRate, knownFrameRate)
+ EXPECT_TRUE(expectedFrameRate.equalsWithMargin(knownFrameRate))
<< "findClosestKnownFrameRate(" << fps << ") = " << knownFrameRate;
}
}
@@ -1465,26 +1480,27 @@
/*currentConfigId=*/HWC_CONFIG_ID_60);
struct ExpectedRate {
- float rate;
+ Fps rate;
const RefreshRate& expected;
};
/* clang-format off */
std::vector<ExpectedRate> knownFrameRatesExpectations = {
- {24.0f, mExpected60Config},
- {30.0f, mExpected60Config},
- {45.0f, mExpected90Config},
- {60.0f, mExpected60Config},
- {72.0f, mExpected90Config},
- {90.0f, mExpected90Config},
+ {Fps(24.0f), mExpected60Config},
+ {Fps(30.0f), mExpected60Config},
+ {Fps(45.0f), mExpected90Config},
+ {Fps(60.0f), mExpected60Config},
+ {Fps(72.0f), mExpected90Config},
+ {Fps(90.0f), mExpected90Config},
};
/* clang-format on */
// Make sure the test tests all the known frame rate
const auto knownFrameRateList = getKnownFrameRate(*refreshRateConfigs);
- const auto equal = std::equal(knownFrameRateList.begin(), knownFrameRateList.end(),
- knownFrameRatesExpectations.begin(),
- [](float a, const ExpectedRate& b) { return a == b.rate; });
+ const auto equal =
+ std::equal(knownFrameRateList.begin(), knownFrameRateList.end(),
+ knownFrameRatesExpectations.begin(),
+ [](Fps a, const ExpectedRate& b) { return a.equalsWithMargin(b.rate); });
EXPECT_TRUE(equal);
auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
@@ -1514,15 +1530,18 @@
EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction());
// SetPolicy(60, 90), current 60Hz => TurnOn.
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 90}}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(90)}}),
+ 0);
EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction());
// SetPolicy(60, 60), current 60Hz => NoChange, avoid extra calls.
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}),
+ 0);
EXPECT_EQ(KernelIdleTimerAction::NoChange, refreshRateConfigs->getIdleTimerAction());
// SetPolicy(90, 90), current 90Hz => TurnOff.
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(90), Fps(90)}}),
+ 0);
EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction());
}
@@ -1554,7 +1573,7 @@
EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDividerForUid(uid));
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
- refreshRateConfigs->setPreferredRefreshRateForUid({uid, 22.5});
+ refreshRateConfigs->setPreferredRefreshRateForUid({uid, 22.5f});
EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDividerForUid(uid));
refreshRateConfigs->setPreferredRefreshRateForUid({uid, 22.6f});
EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDividerForUid(uid));
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index d0bb9e2..e93d0d0 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.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"
-
#undef LOG_TAG
#define LOG_TAG "SchedulerUnittests"
@@ -25,6 +21,8 @@
#include <log/log.h>
#include <thread>
+#include "Scheduler/HwcStrongTypes.h"
+#include "Scheduler/RefreshRateConfigs.h"
#include "Scheduler/RefreshRateStats.h"
#include "mock/DisplayHardware/MockDisplay.h"
#include "mock/MockTimeStats.h"
@@ -51,8 +49,9 @@
void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
mRefreshRateConfigs =
std::make_unique<RefreshRateConfigs>(configs, /*currentConfig=*/CONFIG_ID_0);
- mRefreshRateStats = std::make_unique<RefreshRateStats>(*mRefreshRateConfigs, mTimeStats,
- /*currentConfigId=*/CONFIG_ID_0,
+
+ const auto currFps = mRefreshRateConfigs->getRefreshRateFromConfigId(CONFIG_ID_0).getFps();
+ mRefreshRateStats = std::make_unique<RefreshRateStats>(mTimeStats, currFps,
/*currentPowerMode=*/PowerMode::OFF);
}
@@ -80,8 +79,8 @@
std::shared_ptr<const HWC2::Display::Config> RefreshRateStatsTest::createConfig(
HwcConfigIndexType configId, int32_t configGroup, int64_t vsyncPeriod) {
- return HWC2::Display::Config::Builder(mDisplay, configId.value())
- .setVsyncPeriod(int32_t(vsyncPeriod))
+ return HWC2::Display::Config::Builder(mDisplay, static_cast<hal::HWConfigId>(configId.value()))
+ .setVsyncPeriod(static_cast<int32_t>(vsyncPeriod))
.setConfigGroup(configGroup)
.build();
}
@@ -102,7 +101,7 @@
// Setting up tests on mobile harness can be flaky with time passing, so testing for
// exact time changes can result in flaxy numbers. To avoid that remember old
// numbers to make sure the correct values are increasing in the next test.
- int screenOff = times["ScreenOff"];
+ auto screenOff = times["ScreenOff"];
// Screen is off by default.
std::this_thread::sleep_for(std::chrono::milliseconds(2));
@@ -110,7 +109,8 @@
EXPECT_LT(screenOff, times["ScreenOff"]);
EXPECT_EQ(0u, times.count("90.00fps"));
- mRefreshRateStats->setConfigMode(CONFIG_ID_0);
+ const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromConfigId(CONFIG_ID_0).getFps();
+ mRefreshRateStats->setRefreshRate(config0Fps);
mRefreshRateStats->setPowerMode(PowerMode::ON);
screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
@@ -120,13 +120,13 @@
EXPECT_LT(0, times["90.00fps"]);
mRefreshRateStats->setPowerMode(PowerMode::DOZE);
- int ninety = mRefreshRateStats->getTotalTimes()["90.00fps"];
+ auto ninety = mRefreshRateStats->getTotalTimes()["90.00fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
EXPECT_LT(screenOff, times["ScreenOff"]);
EXPECT_EQ(ninety, times["90.00fps"]);
- mRefreshRateStats->setConfigMode(CONFIG_ID_0);
+ mRefreshRateStats->setRefreshRate(config0Fps);
screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
@@ -150,14 +150,16 @@
// Setting up tests on mobile harness can be flaky with time passing, so testing for
// exact time changes can result in flaxy numbers. To avoid that remember old
// numbers to make sure the correct values are increasing in the next test.
- int screenOff = times["ScreenOff"];
+ auto screenOff = times["ScreenOff"];
// Screen is off by default.
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
EXPECT_LT(screenOff, times["ScreenOff"]);
- mRefreshRateStats->setConfigMode(CONFIG_ID_0);
+ const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromConfigId(CONFIG_ID_0).getFps();
+ const auto config1Fps = mRefreshRateConfigs->getRefreshRateFromConfigId(CONFIG_ID_1).getFps();
+ mRefreshRateStats->setRefreshRate(config0Fps);
mRefreshRateStats->setPowerMode(PowerMode::ON);
screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
@@ -167,8 +169,8 @@
EXPECT_LT(0, times["90.00fps"]);
// When power mode is normal, time for configs updates.
- mRefreshRateStats->setConfigMode(CONFIG_ID_1);
- int ninety = mRefreshRateStats->getTotalTimes()["90.00fps"];
+ mRefreshRateStats->setRefreshRate(config1Fps);
+ auto ninety = mRefreshRateStats->getTotalTimes()["90.00fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
EXPECT_EQ(screenOff, times["ScreenOff"]);
@@ -176,15 +178,15 @@
ASSERT_EQ(1u, times.count("60.00fps"));
EXPECT_LT(0, times["60.00fps"]);
- mRefreshRateStats->setConfigMode(CONFIG_ID_0);
- int sixty = mRefreshRateStats->getTotalTimes()["60.00fps"];
+ mRefreshRateStats->setRefreshRate(config0Fps);
+ auto sixty = mRefreshRateStats->getTotalTimes()["60.00fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
EXPECT_EQ(screenOff, times["ScreenOff"]);
EXPECT_LT(ninety, times["90.00fps"]);
EXPECT_EQ(sixty, times["60.00fps"]);
- mRefreshRateStats->setConfigMode(CONFIG_ID_1);
+ mRefreshRateStats->setRefreshRate(config1Fps);
ninety = mRefreshRateStats->getTotalTimes()["90.00fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
@@ -195,7 +197,7 @@
// Because the power mode is not PowerMode::ON, switching the config
// does not update refresh rates that come from the config.
mRefreshRateStats->setPowerMode(PowerMode::DOZE);
- mRefreshRateStats->setConfigMode(CONFIG_ID_0);
+ mRefreshRateStats->setRefreshRate(config0Fps);
sixty = mRefreshRateStats->getTotalTimes()["60.00fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
@@ -203,7 +205,7 @@
EXPECT_EQ(ninety, times["90.00fps"]);
EXPECT_EQ(sixty, times["60.00fps"]);
- mRefreshRateStats->setConfigMode(CONFIG_ID_1);
+ mRefreshRateStats->setRefreshRate(config1Fps);
screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
@@ -214,6 +216,3 @@
} // namespace
} // namespace scheduler
} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index 5278641..c47b141 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -108,11 +108,12 @@
*/
class SetFrameRateTest : public ::testing::TestWithParam<std::shared_ptr<LayerFactory>> {
protected:
- const FrameRate FRAME_RATE_VOTE1 = FrameRate(67.f, FrameRateCompatibility::Default);
- const FrameRate FRAME_RATE_VOTE2 = FrameRate(14.f, FrameRateCompatibility::ExactOrMultiple);
- const FrameRate FRAME_RATE_VOTE3 = FrameRate(99.f, FrameRateCompatibility::NoVote);
- const FrameRate FRAME_RATE_TREE = FrameRate(0, FrameRateCompatibility::NoVote);
- const FrameRate FRAME_RATE_NO_VOTE = FrameRate(0, FrameRateCompatibility::Default);
+ const FrameRate FRAME_RATE_VOTE1 = FrameRate(Fps(67.f), FrameRateCompatibility::Default);
+ const FrameRate FRAME_RATE_VOTE2 =
+ FrameRate(Fps(14.f), FrameRateCompatibility::ExactOrMultiple);
+ const FrameRate FRAME_RATE_VOTE3 = FrameRate(Fps(99.f), FrameRateCompatibility::NoVote);
+ const FrameRate FRAME_RATE_TREE = FrameRate(Fps(0.f), FrameRateCompatibility::NoVote);
+ const FrameRate FRAME_RATE_NO_VOTE = FrameRate(Fps(0.f), FrameRateCompatibility::Default);
SetFrameRateTest();
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index c0de465..030073c 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -223,12 +223,14 @@
.build());
}
- mFlinger->mRefreshRateConfigs = std::make_unique<
- scheduler::RefreshRateConfigs>(configs, /*currentConfig=*/HwcConfigIndexType(0));
- mFlinger->mRefreshRateStats = std::make_unique<
- scheduler::RefreshRateStats>(*mFlinger->mRefreshRateConfigs, *mFlinger->mTimeStats,
- /*currentConfig=*/HwcConfigIndexType(0),
- /*powerMode=*/hal::PowerMode::OFF);
+ const auto currConfig = HwcConfigIndexType(0);
+ mFlinger->mRefreshRateConfigs =
+ std::make_unique<scheduler::RefreshRateConfigs>(configs, currConfig);
+ const auto currFps =
+ mFlinger->mRefreshRateConfigs->getRefreshRateFromConfigId(currConfig).getFps();
+ mFlinger->mRefreshRateStats =
+ std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mTimeStats, currFps,
+ /*powerMode=*/hal::PowerMode::OFF);
mFlinger->mVsyncConfiguration =
mFactory.createVsyncConfiguration(*mFlinger->mRefreshRateConfigs);
mFlinger->mVsyncModulator.emplace(mFlinger->mVsyncConfiguration->getCurrentConfigs());
diff --git a/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp b/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp
index 72ee6db..2a35f69 100644
--- a/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp
@@ -29,17 +29,18 @@
class TestableWorkDuration : public impl::WorkDuration {
public:
- TestableWorkDuration(float currentFps, nsecs_t sfDuration, nsecs_t appDuration,
+ TestableWorkDuration(Fps currentFps, nsecs_t sfDuration, nsecs_t appDuration,
nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
nsecs_t sfEarlyGlDuration, nsecs_t appEarlyGlDuration)
- : impl::WorkDuration({60.0f, 90.0f}, currentFps, sfDuration, appDuration, sfEarlyDuration,
- appEarlyDuration, sfEarlyGlDuration, appEarlyGlDuration) {}
+ : impl::WorkDuration({Fps(60.0f), Fps(90.0f)}, currentFps, sfDuration, appDuration,
+ sfEarlyDuration, appEarlyDuration, sfEarlyGlDuration,
+ appEarlyGlDuration) {}
};
class WorkDurationTest : public testing::Test {
protected:
WorkDurationTest()
- : mWorkDuration(60.0f, 10'500'000, 20'500'000, 16'000'000, 16'500'000, 13'500'000,
+ : mWorkDuration(Fps(60.0f), 10'500'000, 20'500'000, 16'000'000, 16'500'000, 13'500'000,
21'000'000) {}
~WorkDurationTest() = default;
@@ -51,9 +52,9 @@
* Test cases
*/
TEST_F(WorkDurationTest, getConfigsForRefreshRate_60Hz) {
- mWorkDuration.setRefreshRateFps(60.0f);
+ mWorkDuration.setRefreshRateFps(Fps(60.0f));
auto currentOffsets = mWorkDuration.getCurrentConfigs();
- auto offsets = mWorkDuration.getConfigsForRefreshRate(60.0f);
+ auto offsets = mWorkDuration.getConfigsForRefreshRate(Fps(60.0f));
EXPECT_EQ(currentOffsets, offsets);
EXPECT_EQ(offsets.late.sfOffset, 6'166'667);
@@ -76,9 +77,9 @@
}
TEST_F(WorkDurationTest, getConfigsForRefreshRate_90Hz) {
- mWorkDuration.setRefreshRateFps(90.0f);
+ mWorkDuration.setRefreshRateFps(Fps(90.0f));
auto currentOffsets = mWorkDuration.getCurrentConfigs();
- auto offsets = mWorkDuration.getConfigsForRefreshRate(90.0f);
+ auto offsets = mWorkDuration.getConfigsForRefreshRate(Fps(90.0f));
EXPECT_EQ(currentOffsets, offsets);
EXPECT_EQ(offsets.late.sfOffset, 611'111);
@@ -101,7 +102,7 @@
}
TEST_F(WorkDurationTest, getConfigsForRefreshRate_DefaultOffsets) {
- TestableWorkDuration phaseOffsetsWithDefaultValues(60.0f, -1, -1, -1, -1, -1, -1);
+ TestableWorkDuration phaseOffsetsWithDefaultValues(Fps(60.0f), -1, -1, -1, -1, -1, -1);
auto validateOffsets = [](const auto& offsets, std::chrono::nanoseconds vsyncPeriod) {
EXPECT_EQ(offsets.late.sfOffset, 1'000'000);
@@ -123,21 +124,20 @@
EXPECT_EQ(offsets.earlyGpu.appWorkDuration, vsyncPeriod);
};
- const auto testForRefreshRate = [&](float refreshRate) {
+ const auto testForRefreshRate = [&](Fps refreshRate) {
phaseOffsetsWithDefaultValues.setRefreshRateFps(refreshRate);
auto currentOffsets = phaseOffsetsWithDefaultValues.getCurrentConfigs();
auto offsets = phaseOffsetsWithDefaultValues.getConfigsForRefreshRate(refreshRate);
EXPECT_EQ(currentOffsets, offsets);
- validateOffsets(offsets,
- std::chrono::nanoseconds(static_cast<nsecs_t>(1e9f / refreshRate)));
+ validateOffsets(offsets, std::chrono::nanoseconds(refreshRate.getPeriodNsecs()));
};
- testForRefreshRate(90.0f);
- testForRefreshRate(60.0f);
+ testForRefreshRate(Fps(90.0f));
+ testForRefreshRate(Fps(60.0f));
}
TEST_F(WorkDurationTest, getConfigsForRefreshRate_unknownRefreshRate) {
- auto offsets = mWorkDuration.getConfigsForRefreshRate(14.7f);
+ auto offsets = mWorkDuration.getConfigsForRefreshRate(Fps(14.7f));
EXPECT_EQ(offsets.late.sfOffset, 57'527'208);
EXPECT_EQ(offsets.late.appOffset, 37'027'208);
@@ -171,9 +171,9 @@
std::optional<nsecs_t> highFpsEarlyAppOffsetNs,
std::optional<nsecs_t> highFpsEarlyGpuAppOffsetNs,
nsecs_t thresholdForNextVsync)
- : impl::PhaseOffsets({60.0f, 90.0f}, 60.0f, vsyncPhaseOffsetNs, sfVSyncPhaseOffsetNs,
- earlySfOffsetNs, earlyGpuSfOffsetNs, earlyAppOffsetNs,
- earlyGpuAppOffsetNs, highFpsVsyncPhaseOffsetNs,
+ : impl::PhaseOffsets({Fps(60.0f), Fps(90.0f)}, Fps(60.0f), vsyncPhaseOffsetNs,
+ sfVSyncPhaseOffsetNs, earlySfOffsetNs, earlyGpuSfOffsetNs,
+ earlyAppOffsetNs, earlyGpuAppOffsetNs, highFpsVsyncPhaseOffsetNs,
highFpsSfVSyncPhaseOffsetNs, highFpsEarlySfOffsetNs,
highFpsEarlyGpuSfOffsetNs, highFpsEarlyAppOffsetNs,
highFpsEarlyGpuAppOffsetNs, thresholdForNextVsync) {}
@@ -190,7 +190,7 @@
};
TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_unknownRefreshRate) {
- auto offsets = mPhaseOffsets.getConfigsForRefreshRate(14.7f);
+ auto offsets = mPhaseOffsets.getConfigsForRefreshRate(Fps(14.7f));
EXPECT_EQ(offsets.late.sfOffset, 6'000'000);
EXPECT_EQ(offsets.late.appOffset, 2'000'000);
@@ -212,7 +212,7 @@
}
TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_60Hz) {
- auto offsets = mPhaseOffsets.getConfigsForRefreshRate(60.0f);
+ auto offsets = mPhaseOffsets.getConfigsForRefreshRate(Fps(60.0f));
EXPECT_EQ(offsets.late.sfOffset, 6'000'000);
EXPECT_EQ(offsets.late.appOffset, 2'000'000);
@@ -234,7 +234,7 @@
}
TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_90Hz) {
- auto offsets = mPhaseOffsets.getConfigsForRefreshRate(90.0f);
+ auto offsets = mPhaseOffsets.getConfigsForRefreshRate(Fps(90.0f));
EXPECT_EQ(offsets.late.sfOffset, 1'000'000);
EXPECT_EQ(offsets.late.appOffset, 2'000'000);
@@ -258,7 +258,7 @@
TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_DefaultValues_60Hz) {
TestablePhaseOffsets phaseOffsets{1'000'000, 1'000'000, {}, {}, {}, {}, 2'000'000,
1'000'000, {}, {}, {}, {}, 10'000'000};
- auto offsets = phaseOffsets.getConfigsForRefreshRate(60.0f);
+ auto offsets = phaseOffsets.getConfigsForRefreshRate(Fps(60.0f));
EXPECT_EQ(offsets.late.sfOffset, 1'000'000);
EXPECT_EQ(offsets.late.appOffset, 1'000'000);
@@ -282,7 +282,7 @@
TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_DefaultValues_90Hz) {
TestablePhaseOffsets phaseOffsets{1'000'000, 1'000'000, {}, {}, {}, {}, 2'000'000,
1'000'000, {}, {}, {}, {}, 10'000'000};
- auto offsets = phaseOffsets.getConfigsForRefreshRate(90.0f);
+ auto offsets = phaseOffsets.getConfigsForRefreshRate(Fps(90.0f));
EXPECT_EQ(offsets.late.sfOffset, 1'000'000);
EXPECT_EQ(offsets.late.appOffset, 2'000'000);
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
index 81c32fe..6b12536 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
@@ -31,7 +31,7 @@
MOCK_METHOD0(onBootFinished, void());
MOCK_METHOD2(addSurfaceFrame,
- void(std::unique_ptr<frametimeline::SurfaceFrame>,
+ void(std::shared_ptr<frametimeline::SurfaceFrame>,
frametimeline::SurfaceFrame::PresentState));
MOCK_METHOD2(setSfWakeUp, void(int64_t, nsecs_t));
MOCK_METHOD2(setSfPresent, void(nsecs_t, const std::shared_ptr<FenceTime>&));
diff --git a/services/vibratorservice/Android.bp b/services/vibratorservice/Android.bp
index 75228d6..c18bf18 100644
--- a/services/vibratorservice/Android.bp
+++ b/services/vibratorservice/Android.bp
@@ -19,6 +19,7 @@
"VibratorCallbackScheduler.cpp",
"VibratorHalController.cpp",
"VibratorHalWrapper.cpp",
+ "VibratorManagerHalController.cpp",
"VibratorManagerHalWrapper.cpp",
],
diff --git a/services/vibratorservice/VibratorManagerHalController.cpp b/services/vibratorservice/VibratorManagerHalController.cpp
index b24e5c4..6bf6581 100644
--- a/services/vibratorservice/VibratorManagerHalController.cpp
+++ b/services/vibratorservice/VibratorManagerHalController.cpp
@@ -26,13 +26,13 @@
namespace vibrator {
-std::shared_ptr<ManagerHalWrapper> connectHal(std::shared_ptr<CallbackScheduler> scheduler) {
+std::shared_ptr<ManagerHalWrapper> connectManagerHal(std::shared_ptr<CallbackScheduler> scheduler) {
static bool gHalExists = true;
if (gHalExists) {
sp<Aidl::IVibratorManager> hal = waitForVintfService<Aidl::IVibratorManager>();
if (hal) {
ALOGV("Successfully connected to VibratorManager HAL AIDL service.");
- return std::make_shared<AidlManagerHalWrapper>(std::move(scheduler), aidlHal);
+ return std::make_shared<AidlManagerHalWrapper>(std::move(scheduler), hal);
}
}
@@ -80,12 +80,11 @@
// -------------------------------------------------------------------------------------------------
-bool ManagerHalController::init() {
+void ManagerHalController::init() {
std::lock_guard<std::mutex> lock(mConnectedHalMutex);
if (mConnectedHal == nullptr) {
mConnectedHal = mConnector(mCallbackScheduler);
}
- return mConnectedHal != nullptr;
}
HalResult<void> ManagerHalController::ping() {
diff --git a/services/vibratorservice/include/vibratorservice/VibratorManagerHalController.h b/services/vibratorservice/include/vibratorservice/VibratorManagerHalController.h
index cf82562..9168565 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorManagerHalController.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorManagerHalController.h
@@ -19,6 +19,7 @@
#include <android/hardware/vibrator/IVibratorManager.h>
#include <vibratorservice/VibratorHalController.h>
+#include <vibratorservice/VibratorManagerHalWrapper.h>
#include <unordered_map>
namespace android {
@@ -36,7 +37,7 @@
ManagerHalController()
: ManagerHalController(std::make_shared<CallbackScheduler>(), &connectManagerHal) {}
ManagerHalController(std::shared_ptr<CallbackScheduler> callbackScheduler, Connector connector)
- : mConnector(connector), mConnectedHal(nullptr) {}
+ : mConnector(connector), mCallbackScheduler(callbackScheduler), mConnectedHal(nullptr) {}
virtual ~ManagerHalController() = default;
/* Connects to the HAL service, possibly waiting for the registered service to
@@ -64,9 +65,10 @@
private:
Connector mConnector;
+ std::shared_ptr<CallbackScheduler> mCallbackScheduler;
std::mutex mConnectedHalMutex;
// Shared pointer to allow local copies to be used by different threads.
- std::shared_ptr<HalWrapper> mConnectedHal GUARDED_BY(mConnectedHalMutex);
+ std::shared_ptr<ManagerHalWrapper> mConnectedHal GUARDED_BY(mConnectedHalMutex);
template <typename T>
HalResult<T> processHalResult(HalResult<T> result, const char* functionName);
diff --git a/services/vibratorservice/test/Android.bp b/services/vibratorservice/test/Android.bp
index 6801f76..9af1b7b 100644
--- a/services/vibratorservice/test/Android.bp
+++ b/services/vibratorservice/test/Android.bp
@@ -23,6 +23,7 @@
"VibratorHalWrapperHidlV1_1Test.cpp",
"VibratorHalWrapperHidlV1_2Test.cpp",
"VibratorHalWrapperHidlV1_3Test.cpp",
+ "VibratorManagerHalControllerTest.cpp",
"VibratorManagerHalWrapperAidlTest.cpp",
"VibratorManagerHalWrapperLegacyTest.cpp",
],
diff --git a/services/vibratorservice/test/VibratorManagerHalControllerTest.cpp b/services/vibratorservice/test/VibratorManagerHalControllerTest.cpp
index 3b036ee..e5fbbae 100644
--- a/services/vibratorservice/test/VibratorManagerHalControllerTest.cpp
+++ b/services/vibratorservice/test/VibratorManagerHalControllerTest.cpp
@@ -22,22 +22,28 @@
#include <utils/Log.h>
-#include <vibratorservice/VibratorManagerHalWrapper.h>
+#include <vibratorservice/VibratorManagerHalController.h>
#include "test_utils.h"
+using android::vibrator::HalController;
+
using namespace android;
using namespace testing;
static constexpr int MAX_ATTEMPTS = 2;
+static const std::vector<int32_t> VIBRATOR_IDS = {1, 2};
+static constexpr int VIBRATOR_ID = 1;
class MockManagerHalWrapper : public vibrator::ManagerHalWrapper {
public:
+ MOCK_METHOD(void, tryReconnect, (), (override));
MOCK_METHOD(vibrator::HalResult<void>, ping, (), (override));
- MOCK_METHOD(vibrator::HalResult<int32_t>, getCapabilities, (), (override));
+ MOCK_METHOD(vibrator::HalResult<vibrator::ManagerCapabilities>, getCapabilities, (),
+ (override));
MOCK_METHOD(vibrator::HalResult<std::vector<int32_t>>, getVibratorIds, (), (override));
- MOCK_METHOD(vibrator::HalResult<std::shared_ptr<vibrator::HalController>>, getVibrator,
- (int32_t id), (override));
+ MOCK_METHOD(vibrator::HalResult<std::shared_ptr<HalController>>, getVibrator, (int32_t id),
+ (override));
MOCK_METHOD(vibrator::HalResult<void>, prepareSynced, (const std::vector<int32_t>& ids),
(override));
MOCK_METHOD(vibrator::HalResult<void>, triggerSynced,
@@ -50,13 +56,13 @@
void SetUp() override {
mConnectCounter = 0;
auto callbackScheduler = std::make_shared<vibrator::CallbackScheduler>();
- mMockHal = std::make_shared<StrictMock<MockHalWrapper>>(callbackScheduler);
- mController = std::make_unique<
- vibrator::HalController>(std::move(callbackScheduler),
- [&](std::shared_ptr<vibrator::CallbackScheduler>) {
- android_atomic_inc(&(this->mConnectCounter));
- return this->mMockHal;
- });
+ mMockHal = std::make_shared<StrictMock<MockManagerHalWrapper>>();
+ auto connector = [this](std::shared_ptr<vibrator::CallbackScheduler>) {
+ android_atomic_inc(&mConnectCounter);
+ return mMockHal;
+ };
+ mController = std::make_unique<vibrator::ManagerHalController>(std::move(callbackScheduler),
+ connector);
ASSERT_NE(mController, nullptr);
}
@@ -65,8 +71,7 @@
std::shared_ptr<MockManagerHalWrapper> mMockHal;
std::unique_ptr<vibrator::ManagerHalController> mController;
- void setHalExpectations(int32_t cardinality, std::vector<int32_t> ids,
- vibrator::HalResult<void> voidResult,
+ void setHalExpectations(int32_t cardinality, vibrator::HalResult<void> voidResult,
vibrator::HalResult<vibrator::ManagerCapabilities> capabilitiesResult,
vibrator::HalResult<std::vector<int32_t>> idsResult,
vibrator::HalResult<std::shared_ptr<HalController>> vibratorResult) {
@@ -100,24 +105,20 @@
};
TEST_F(VibratorManagerHalControllerTest, TestInit) {
- ASSERT_TRUE(mController->init());
+ mController->init();
ASSERT_EQ(1, mConnectCounter);
// Noop when wrapper was already initialized.
- ASSERT_TRUE(mController->init());
+ mController->init();
ASSERT_EQ(1, mConnectCounter);
}
TEST_F(VibratorManagerHalControllerTest, TestApiCallsAreForwardedToHal) {
- std::vector<int32_t> ids;
- ids.push_back(1);
- ids.push_back(2);
-
- setHalExpectations(/* cardinality= */ 1, ids, vibrator::HalResult<void>::ok(),
+ setHalExpectations(/* cardinality= */ 1, vibrator::HalResult<void>::ok(),
vibrator::HalResult<vibrator::ManagerCapabilities>::ok(
vibrator::ManagerCapabilities::SYNC),
- vibrator::HalResult<std::vector<int32_t>>::ok(ids),
- vibrator::HalResult<std::shared_ptr<vibrator::HalController>>::ok(nullptr));
+ vibrator::HalResult<std::vector<int32_t>>::ok(VIBRATOR_IDS),
+ vibrator::HalResult<std::shared_ptr<HalController>>::ok(nullptr));
ASSERT_TRUE(mController->ping().isOk());
@@ -127,13 +128,13 @@
auto getVibratorIdsResult = mController->getVibratorIds();
ASSERT_TRUE(getVibratorIdsResult.isOk());
- ASSERT_EQ(ids, getVibratorIdsResult.value());
+ ASSERT_EQ(VIBRATOR_IDS, getVibratorIdsResult.value());
- auto getVibratorResult = mController->getVibrator(1);
+ auto getVibratorResult = mController->getVibrator(VIBRATOR_ID);
ASSERT_TRUE(getVibratorResult.isOk());
ASSERT_EQ(nullptr, getVibratorResult.value());
- ASSERT_TRUE(mController->prepareSynced(ids).isOk());
+ ASSERT_TRUE(mController->prepareSynced(VIBRATOR_IDS).isOk());
ASSERT_TRUE(mController->triggerSynced([]() {}).isOk());
ASSERT_TRUE(mController->cancelSynced().isOk());
@@ -141,20 +142,18 @@
}
TEST_F(VibratorManagerHalControllerTest, TestUnsupportedApiResultDoNotResetHalConnection) {
- std::vector<int32_t> ids;
- setHalExpectations(/* cardinality= */ 1, ids, vibrator::HalResult<void>::unsupported(),
+ setHalExpectations(/* cardinality= */ 1, vibrator::HalResult<void>::unsupported(),
vibrator::HalResult<vibrator::ManagerCapabilities>::unsupported(),
vibrator::HalResult<std::vector<int32_t>>::unsupported(),
- vibrator::HalResult<
- std::shared_ptr<vibrator::HalController>>::unsupported());
+ vibrator::HalResult<std::shared_ptr<HalController>>::unsupported());
ASSERT_EQ(0, mConnectCounter);
ASSERT_TRUE(mController->ping().isUnsupported());
ASSERT_TRUE(mController->getCapabilities().isUnsupported());
ASSERT_TRUE(mController->getVibratorIds().isUnsupported());
- ASSERT_TRUE(mController->getVibrator(1).isUnsupported());
- ASSERT_TRUE(mController->prepareSynced(ids).isUnsupported());
+ ASSERT_TRUE(mController->getVibrator(VIBRATOR_ID).isUnsupported());
+ ASSERT_TRUE(mController->prepareSynced(VIBRATOR_IDS).isUnsupported());
ASSERT_TRUE(mController->triggerSynced([]() {}).isUnsupported());
ASSERT_TRUE(mController->cancelSynced().isUnsupported());
@@ -162,20 +161,18 @@
}
TEST_F(VibratorManagerHalControllerTest, TestFailedApiResultResetsHalConnection) {
- std::vector<int32_t> ids;
- setHalExpectations(/* cardinality= */ 1, ids, vibrator::HalResult<void>::failed("message"),
+ setHalExpectations(MAX_ATTEMPTS, vibrator::HalResult<void>::failed("message"),
vibrator::HalResult<vibrator::ManagerCapabilities>::failed("message"),
vibrator::HalResult<std::vector<int32_t>>::failed("message"),
- vibrator::HalResult<std::shared_ptr<vibrator::HalController>>::failed(
- "message"));
+ vibrator::HalResult<std::shared_ptr<HalController>>::failed("message"));
ASSERT_EQ(0, mConnectCounter);
ASSERT_TRUE(mController->ping().isFailed());
ASSERT_TRUE(mController->getCapabilities().isFailed());
ASSERT_TRUE(mController->getVibratorIds().isFailed());
- ASSERT_TRUE(mController->getVibrator(1).isFailed());
- ASSERT_TRUE(mController->prepareSynced(ids).isFailed());
+ ASSERT_TRUE(mController->getVibrator(VIBRATOR_ID).isFailed());
+ ASSERT_TRUE(mController->prepareSynced(VIBRATOR_IDS).isFailed());
ASSERT_TRUE(mController->triggerSynced([]() {}).isFailed());
ASSERT_TRUE(mController->cancelSynced().isFailed());