diff options
102 files changed, 2487 insertions, 1055 deletions
diff --git a/data/etc/Android.bp b/data/etc/Android.bp index 931c5e3f2a..1be3a69a7d 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -191,6 +191,12 @@ prebuilt_etc { } prebuilt_etc { + name: "android.hardware.wifi.direct.prebuilt.xml", + src: "android.hardware.wifi.direct.xml", + defaults: ["frameworks_native_data_etc_defaults"], +} + +prebuilt_etc { name: "android.hardware.wifi.passpoint.prebuilt.xml", src: "android.hardware.wifi.passpoint.xml", defaults: ["frameworks_native_data_etc_defaults"], diff --git a/include/ftl/concat.h b/include/ftl/concat.h new file mode 100644 index 0000000000..ded48f7c8c --- /dev/null +++ b/include/ftl/concat.h @@ -0,0 +1,84 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <ftl/details/concat.h> + +namespace android::ftl { + +// Lightweight (not allocating nor sprintf-based) concatenation. +// +// std::string_view name = "Volume"; +// ftl::Concat string(ftl::truncated<3>(name), ": ", -3, " dB"); +// +// assert(string.str() == "Vol: -3 dB"); +// assert(string.c_str()[string.size()] == '\0'); +// +template <std::size_t, typename... Ts> +struct Concat; + +template <std::size_t N, typename T, typename... Ts> +struct Concat<N, T, Ts...> : Concat<N + details::StaticString<T>::N, Ts...> { + explicit constexpr Concat(T v, Ts... args) { append(v, args...); } + + protected: + constexpr Concat() = default; + + constexpr void append(T v, Ts... args) { + using Str = details::StaticString<T>; + const Str str(v); + + // TODO: Replace with constexpr std::copy in C++20. + for (auto it = str.view.begin(); it != str.view.end();) { + *this->end_++ = *it++; + } + + using Base = Concat<N + Str::N, Ts...>; + this->Base::append(args...); + } +}; + +template <std::size_t N> +struct Concat<N> { + static constexpr std::size_t max_size() { return N; } + constexpr std::size_t size() const { return end_ - buffer_; } + + constexpr const char* c_str() const { return buffer_; } + + constexpr std::string_view str() const { + // TODO: Replace with {buffer_, end_} in C++20. + return {buffer_, size()}; + } + + protected: + constexpr Concat() : end_(buffer_) {} + constexpr void append() { *end_ = '\0'; } + + char buffer_[N + 1]; + char* end_; +}; + +// Deduction guide. +template <typename... Ts> +Concat(Ts&&...) -> Concat<0, Ts...>; + +template <std::size_t N> +constexpr auto truncated(std::string_view v) { + return details::Truncated<N>{v}; +} + +} // namespace android::ftl diff --git a/include/ftl/details/concat.h b/include/ftl/details/concat.h new file mode 100644 index 0000000000..8ce949ef05 --- /dev/null +++ b/include/ftl/details/concat.h @@ -0,0 +1,62 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <functional> +#include <string_view> + +#include <ftl/string.h> + +namespace android::ftl::details { + +template <typename T, typename = void> +struct StaticString; + +template <typename T> +struct StaticString<T, std::enable_if_t<std::is_integral_v<T>>> { + static constexpr std::size_t N = to_chars_length_v<T>; + + explicit StaticString(T v) : view(to_chars(buffer, v)) {} + + to_chars_buffer_t<T> buffer; + const std::string_view view; +}; + +template <std::size_t M> +struct StaticString<const char (&)[M], void> { + static constexpr std::size_t N = M - 1; + + explicit constexpr StaticString(const char (&str)[M]) : view(str, N) {} + + const std::string_view view; +}; + +template <std::size_t N> +struct Truncated { + std::string_view view; +}; + +template <std::size_t M> +struct StaticString<Truncated<M>, void> { + static constexpr std::size_t N = M; + + explicit constexpr StaticString(Truncated<M> str) : view(str.view.substr(0, N)) {} + + const std::string_view view; +}; + +} // namespace android::ftl::details diff --git a/include/input/Input.h b/include/input/Input.h index ddff144954..f4147a0409 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -31,10 +31,8 @@ #include <stdint.h> #include <ui/Transform.h> #include <utils/BitSet.h> -#include <utils/KeyedVector.h> #include <utils/RefBase.h> #include <utils/Timers.h> -#include <utils/Vector.h> #include <array> #include <limits> #include <queue> @@ -88,7 +86,7 @@ enum { */ AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40, -#ifdef __linux__ +#if defined(__linux__) /** * This event was generated or modified by accessibility service. */ @@ -799,11 +797,11 @@ public: // Low-level accessors. inline const PointerProperties* getPointerProperties() const { - return mPointerProperties.array(); + return mPointerProperties.data(); } inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.data(); } inline const PointerCoords* getSamplePointerCoords() const { - return mSamplePointerCoords.array(); + return mSamplePointerCoords.data(); } static const char* getLabel(int32_t axis); @@ -834,9 +832,9 @@ protected: float mRawYCursorPosition; ui::Transform mRawTransform; nsecs_t mDownTime; - Vector<PointerProperties> mPointerProperties; + std::vector<PointerProperties> mPointerProperties; std::vector<nsecs_t> mSampleEventTimes; - Vector<PointerCoords> mSamplePointerCoords; + std::vector<PointerCoords> mSamplePointerCoords; }; /* diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h index f5abb859bc..706783093c 100644 --- a/libs/binder/include/binder/IInterface.h +++ b/libs/binder/include/binder/IInterface.h @@ -93,20 +93,20 @@ protected: // ---------------------------------------------------------------------- -#define DECLARE_META_INTERFACE(INTERFACE) \ -public: \ - static const ::android::String16 descriptor; \ - static ::android::sp<I##INTERFACE> asInterface( \ - const ::android::sp<::android::IBinder>& obj); \ - virtual const ::android::String16& getInterfaceDescriptor() const; \ - I##INTERFACE(); \ - virtual ~I##INTERFACE(); \ - static bool setDefaultImpl(std::unique_ptr<I##INTERFACE> impl); \ - static const std::unique_ptr<I##INTERFACE>& getDefaultImpl(); \ -private: \ - static std::unique_ptr<I##INTERFACE> default_impl; \ -public: \ - +#define DECLARE_META_INTERFACE(INTERFACE) \ +public: \ + static const ::android::String16 descriptor; \ + static ::android::sp<I##INTERFACE> asInterface(const ::android::sp<::android::IBinder>& obj); \ + virtual const ::android::String16& getInterfaceDescriptor() const; \ + I##INTERFACE(); \ + virtual ~I##INTERFACE(); \ + static bool setDefaultImpl(::android::sp<I##INTERFACE> impl); \ + static const ::android::sp<I##INTERFACE>& getDefaultImpl(); \ + \ +private: \ + static ::android::sp<I##INTERFACE> default_impl; \ + \ +public: #define __IINTF_CONCAT(x, y) (x ## y) @@ -142,8 +142,8 @@ public: \ } \ return intr; \ } \ - std::unique_ptr<ITYPE> ITYPE::default_impl; \ - bool ITYPE::setDefaultImpl(std::unique_ptr<ITYPE> impl) { \ + ::android::sp<ITYPE> ITYPE::default_impl; \ + bool ITYPE::setDefaultImpl(::android::sp<ITYPE> impl) { \ /* Only one user of this interface can use this function */ \ /* at a time. This is a heuristic to detect if two different */ \ /* users in the same process use this function. */ \ @@ -154,7 +154,7 @@ public: \ } \ return false; \ } \ - const std::unique_ptr<ITYPE>& ITYPE::getDefaultImpl() { return ITYPE::default_impl; } \ + const ::android::sp<ITYPE>& ITYPE::getDefaultImpl() { return ITYPE::default_impl; } \ ITYPE::INAME() {} \ ITYPE::~INAME() {} diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs index 206b90c807..256fa8bea6 100644 --- a/libs/binder/rust/src/parcel.rs +++ b/libs/binder/rust/src/parcel.rs @@ -496,7 +496,7 @@ impl<'a> BorrowedParcel<'a> { { let start = self.get_data_position(); let parcelable_size: i32 = self.read()?; - if parcelable_size < 0 { + if parcelable_size < 4 { return Err(StatusCode::BAD_VALUE); } diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 5a80ad067c..bc2eb23677 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -16,6 +16,7 @@ cc_test { srcs: [ "Flags_test.cpp", "cast_test.cpp", + "concat_test.cpp", "enum_test.cpp", "future_test.cpp", "small_map_test.cpp", diff --git a/libs/ftl/concat_test.cpp b/libs/ftl/concat_test.cpp new file mode 100644 index 0000000000..8ecb1b252d --- /dev/null +++ b/libs/ftl/concat_test.cpp @@ -0,0 +1,55 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <ftl/concat.h> +#include <gtest/gtest.h> + +namespace android::test { + +// Keep in sync with example usage in header file. +TEST(Concat, Example) { + std::string_view name = "Volume"; + ftl::Concat string(ftl::truncated<3>(name), ": ", -3, " dB"); + + EXPECT_EQ(string.str(), "Vol: -3 dB"); + EXPECT_EQ(string.c_str()[string.size()], '\0'); +} + +namespace { + +static_assert(ftl::Concat{"foo"}.str() == "foo"); +static_assert(ftl::Concat{ftl::truncated<3>("foobar")}.str() == "foo"); + +constexpr ftl::Concat kConcat{"po", "trz", "ebie"}; + +static_assert(kConcat.size() == 9); +static_assert(kConcat.max_size() == 9); +static_assert(kConcat.str() == "potrzebie"); +static_assert(kConcat.str() == std::string_view(kConcat.c_str())); + +constexpr auto concat() { + return ftl::Concat{ftl::truncated<1>("v???"), ftl::truncated<2>("ee??"), + ftl::truncated<3>("ble?"), ftl::truncated<4>("fetz"), + ftl::truncated<90>("er")}; +} + +static_assert(concat().size() == 12); +static_assert(concat().max_size() == 100); +static_assert(concat().str() == "veeblefetzer"); +static_assert(concat().str() == std::string_view(concat().c_str())); + +} // namespace +} // namespace android::test diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 84dba84e2b..3073d94dbe 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -456,7 +456,8 @@ void MotionEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int3 mRawTransform = rawTransform; mDownTime = downTime; mPointerProperties.clear(); - mPointerProperties.appendArray(pointerProperties, pointerCount); + mPointerProperties.insert(mPointerProperties.end(), &pointerProperties[0], + &pointerProperties[pointerCount]); mSampleEventTimes.clear(); mSamplePointerCoords.clear(); addSample(eventTime, pointerCoords); @@ -490,8 +491,10 @@ void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { mSamplePointerCoords.clear(); size_t pointerCount = other->getPointerCount(); size_t historySize = other->getHistorySize(); - mSamplePointerCoords.appendArray(other->mSamplePointerCoords.array() - + (historySize * pointerCount), pointerCount); + mSamplePointerCoords + .insert(mSamplePointerCoords.end(), + &other->mSamplePointerCoords[historySize * pointerCount], + &other->mSamplePointerCoords[historySize * pointerCount + pointerCount]); } } @@ -499,7 +502,8 @@ void MotionEvent::addSample( int64_t eventTime, const PointerCoords* pointerCoords) { mSampleEventTimes.push_back(eventTime); - mSamplePointerCoords.appendArray(pointerCoords, getPointerCount()); + mSamplePointerCoords.insert(mSamplePointerCoords.end(), &pointerCoords[0], + &pointerCoords[getPointerCount()]); } int MotionEvent::getSurfaceRotation() const { @@ -569,7 +573,7 @@ float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const { size_t pointerCount = mPointerProperties.size(); for (size_t i = 0; i < pointerCount; i++) { - if (mPointerProperties.itemAt(i).id == pointerId) { + if (mPointerProperties[i].id == pointerId) { return i; } } @@ -591,8 +595,7 @@ void MotionEvent::scale(float globalScaleFactor) { size_t numSamples = mSamplePointerCoords.size(); for (size_t i = 0; i < numSamples; i++) { - mSamplePointerCoords.editItemAt(i).scale(globalScaleFactor, globalScaleFactor, - globalScaleFactor); + mSamplePointerCoords[i].scale(globalScaleFactor, globalScaleFactor, globalScaleFactor); } } @@ -686,15 +689,15 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { mDownTime = parcel->readInt64(); mPointerProperties.clear(); - mPointerProperties.setCapacity(pointerCount); + mPointerProperties.reserve(pointerCount); mSampleEventTimes.clear(); mSampleEventTimes.reserve(sampleCount); mSamplePointerCoords.clear(); - mSamplePointerCoords.setCapacity(sampleCount * pointerCount); + mSamplePointerCoords.reserve(sampleCount * pointerCount); for (size_t i = 0; i < pointerCount; i++) { - mPointerProperties.push(); - PointerProperties& properties = mPointerProperties.editTop(); + mPointerProperties.push_back({}); + PointerProperties& properties = mPointerProperties.back(); properties.id = parcel->readInt32(); properties.toolType = parcel->readInt32(); } @@ -703,8 +706,8 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { sampleCount--; mSampleEventTimes.push_back(parcel->readInt64()); for (size_t i = 0; i < pointerCount; i++) { - mSamplePointerCoords.push(); - status_t status = mSamplePointerCoords.editTop().readFromParcel(parcel); + mSamplePointerCoords.push_back({}); + status_t status = mSamplePointerCoords.back().readFromParcel(parcel); if (status) { return status; } @@ -750,12 +753,12 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeInt64(mDownTime); for (size_t i = 0; i < pointerCount; i++) { - const PointerProperties& properties = mPointerProperties.itemAt(i); + const PointerProperties& properties = mPointerProperties[i]; parcel->writeInt32(properties.id); parcel->writeInt32(properties.toolType); } - const PointerCoords* pc = mSamplePointerCoords.array(); + const PointerCoords* pc = mSamplePointerCoords.data(); for (size_t h = 0; h < sampleCount; h++) { parcel->writeInt64(mSampleEventTimes[h]); for (size_t i = 0; i < pointerCount; i++) { diff --git a/libs/renderengine/ExternalTexture.cpp b/libs/renderengine/ExternalTexture.cpp index eabff58eba..84771c0917 100644 --- a/libs/renderengine/ExternalTexture.cpp +++ b/libs/renderengine/ExternalTexture.cpp @@ -14,30 +14,32 @@ * limitations under the License. */ -#include <renderengine/ExternalTexture.h> #include <renderengine/RenderEngine.h> +#include <renderengine/impl/ExternalTexture.h> #include <ui/GraphicBuffer.h> #include "log/log_main.h" -namespace android::renderengine { +namespace android::renderengine::impl { -ExternalTexture::ExternalTexture(const sp<GraphicBuffer>& buffer, RenderEngine& renderEngine, - uint32_t usage) +ExternalTexture::ExternalTexture(const sp<GraphicBuffer>& buffer, + renderengine::RenderEngine& renderEngine, uint32_t usage) : mBuffer(buffer), mRenderEngine(renderEngine) { LOG_ALWAYS_FATAL_IF(buffer == nullptr, "Attempted to bind a null buffer to an external texture!"); // GLESRenderEngine has a separate texture cache for output buffers, - if (usage == Usage::WRITEABLE && - (mRenderEngine.getRenderEngineType() == RenderEngine::RenderEngineType::GLES || - mRenderEngine.getRenderEngineType() == RenderEngine::RenderEngineType::THREADED)) { + if (usage == WRITEABLE && + (mRenderEngine.getRenderEngineType() == + renderengine::RenderEngine::RenderEngineType::GLES || + mRenderEngine.getRenderEngineType() == + renderengine::RenderEngine::RenderEngineType::THREADED)) { return; } - mRenderEngine.mapExternalTextureBuffer(mBuffer, usage & Usage::WRITEABLE); + mRenderEngine.mapExternalTextureBuffer(mBuffer, usage & WRITEABLE); } ExternalTexture::~ExternalTexture() { mRenderEngine.unmapExternalTextureBuffer(mBuffer); } -} // namespace android::renderengine +} // namespace android::renderengine::impl diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp index 6c8f8e878b..ead97cf5df 100644 --- a/libs/renderengine/benchmark/RenderEngineBench.cpp +++ b/libs/renderengine/benchmark/RenderEngineBench.cpp @@ -22,6 +22,7 @@ #include <renderengine/ExternalTexture.h> #include <renderengine/LayerSettings.h> #include <renderengine/RenderEngine.h> +#include <renderengine/impl/ExternalTexture.h> #include <mutex> @@ -115,15 +116,15 @@ static std::shared_ptr<ExternalTexture> allocateBuffer(RenderEngine& re, uint32_ uint32_t height, uint64_t extraUsageFlags = 0, std::string name = "output") { - return std::make_shared<ExternalTexture>(new GraphicBuffer(width, height, - HAL_PIXEL_FORMAT_RGBA_8888, 1, - GRALLOC_USAGE_HW_RENDER | - GRALLOC_USAGE_HW_TEXTURE | - extraUsageFlags, - std::move(name)), - re, - ExternalTexture::Usage::READABLE | - ExternalTexture::Usage::WRITEABLE); + return std::make_shared< + impl::ExternalTexture>(new GraphicBuffer(width, height, HAL_PIXEL_FORMAT_RGBA_8888, 1, + GRALLOC_USAGE_HW_RENDER | + GRALLOC_USAGE_HW_TEXTURE | + extraUsageFlags, + std::move(name)), + re, + impl::ExternalTexture::Usage::READABLE | + impl::ExternalTexture::Usage::WRITEABLE); } static std::shared_ptr<ExternalTexture> copyBuffer(RenderEngine& re, diff --git a/libs/renderengine/include/renderengine/ExternalTexture.h b/libs/renderengine/include/renderengine/ExternalTexture.h index 07f0833d4a..621a209afa 100644 --- a/libs/renderengine/include/renderengine/ExternalTexture.h +++ b/libs/renderengine/include/renderengine/ExternalTexture.h @@ -33,28 +33,22 @@ class RenderEngine; */ class ExternalTexture { public: - // Usage specifies the rendering intent for the buffer. - enum Usage : uint32_t { - // When a buffer is not READABLE but is WRITEABLE, then GLESRenderEngine will use that as a - // hint to load the buffer into a separate cache - READABLE = 1 << 0, - - // The buffer needs to be mapped as a 2D texture if set, otherwise must be mapped as an - // external texture - WRITEABLE = 1 << 1, - }; - // Creates an ExternalTexture for the provided buffer and RenderEngine instance, with the given - // usage hint of type Usage. - ExternalTexture(const sp<GraphicBuffer>& buffer, RenderEngine& renderEngine, uint32_t usage); - - ~ExternalTexture(); + ExternalTexture() = default; + virtual ~ExternalTexture() = default; + + virtual bool hasSameBuffer(const ExternalTexture& other) const = 0; + virtual uint32_t getWidth() const = 0; + virtual uint32_t getHeight() const = 0; + virtual uint64_t getId() const = 0; + virtual PixelFormat getPixelFormat() const = 0; + virtual uint64_t getUsage() const = 0; // Retrieves the buffer that is bound to this texture. - const sp<GraphicBuffer>& getBuffer() const { return mBuffer; } + virtual const sp<GraphicBuffer>& getBuffer() const = 0; -private: - sp<GraphicBuffer> mBuffer; - RenderEngine& mRenderEngine; + Rect getBounds() const { + return {0, 0, static_cast<int32_t>(getWidth()), static_cast<int32_t>(getHeight())}; + } DISALLOW_COPY_AND_ASSIGN(ExternalTexture); }; diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index d646756fc4..faa84fc1cd 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -76,6 +76,7 @@ class RenderEngineThreaded; namespace impl { class RenderEngine; +class ExternalTexture; } enum class Protection { @@ -228,7 +229,7 @@ protected: // avoid any thread synchronization that may be required by directly calling postRenderCleanup. virtual bool canSkipPostRenderCleanup() const = 0; - friend class ExternalTexture; + friend class impl::ExternalTexture; friend class threaded::RenderEngineThreaded; friend class RenderEngineTest_cleanupPostRender_cleansUpOnce_Test; const RenderEngineType mRenderEngineType; diff --git a/libs/renderengine/include/renderengine/impl/ExternalTexture.h b/libs/renderengine/include/renderengine/impl/ExternalTexture.h new file mode 100644 index 0000000000..c0e24f0c10 --- /dev/null +++ b/libs/renderengine/include/renderengine/impl/ExternalTexture.h @@ -0,0 +1,60 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <android-base/macros.h> +#include <renderengine/ExternalTexture.h> +#include <ui/GraphicBuffer.h> + +namespace android::renderengine::impl { + +class RenderEngine; + +class ExternalTexture : public android::renderengine::ExternalTexture { +public: + // Usage specifies the rendering intent for the buffer. + enum Usage : uint32_t { + // When a buffer is not READABLE but is WRITEABLE, then GLESRenderEngine will use that as a + // hint to load the buffer into a separate cache + READABLE = 1 << 0, + + // The buffer needs to be mapped as a 2D texture if set, otherwise must be mapped as an + // external texture + WRITEABLE = 1 << 1, + }; + + // Creates an ExternalTexture for the provided buffer and RenderEngine instance, with the given + // usage hint of type Usage. + ExternalTexture(const sp<GraphicBuffer>& buffer, + android::renderengine::RenderEngine& renderEngine, uint32_t usage); + ~ExternalTexture(); + const sp<GraphicBuffer>& getBuffer() const override { return mBuffer; }; + uint32_t getWidth() const override { return getBuffer()->getWidth(); } + uint32_t getHeight() const override { return getBuffer()->getHeight(); } + uint64_t getId() const override { return getBuffer()->getId(); } + PixelFormat getPixelFormat() const override { return getBuffer()->getPixelFormat(); } + uint64_t getUsage() const override { return getBuffer()->getUsage(); } + bool hasSameBuffer(const renderengine::ExternalTexture& other) const override { + return getBuffer() == other.getBuffer(); + } + +private: + sp<GraphicBuffer> mBuffer; + android::renderengine::RenderEngine& mRenderEngine; +}; + +} // namespace android::renderengine::impl diff --git a/libs/renderengine/include/renderengine/mock/FakeExternalTexture.h b/libs/renderengine/include/renderengine/mock/FakeExternalTexture.h new file mode 100644 index 0000000000..974e0fddde --- /dev/null +++ b/libs/renderengine/include/renderengine/mock/FakeExternalTexture.h @@ -0,0 +1,51 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <renderengine/ExternalTexture.h> + +namespace android { +namespace renderengine { +namespace mock { + +class FakeExternalTexture : public renderengine::ExternalTexture { + const sp<GraphicBuffer> mNullBuffer = nullptr; + uint32_t mWidth; + uint32_t mHeight; + uint64_t mId; + PixelFormat mPixelFormat; + uint64_t mUsage; + +public: + FakeExternalTexture(uint32_t width, uint32_t height, uint64_t id, PixelFormat pixelFormat, + uint64_t usage) + : mWidth(width), mHeight(height), mId(id), mPixelFormat(pixelFormat), mUsage(usage) {} + const sp<GraphicBuffer>& getBuffer() const { return mNullBuffer; } + bool hasSameBuffer(const renderengine::ExternalTexture& other) const override { + return getId() == other.getId(); + } + uint32_t getWidth() const override { return mWidth; } + uint32_t getHeight() const override { return mHeight; } + uint64_t getId() const override { return mId; } + PixelFormat getPixelFormat() const override { return mPixelFormat; } + uint64_t getUsage() const override { return mUsage; } + ~FakeExternalTexture() = default; +}; + +} // namespace mock +} // namespace renderengine +} // namespace android diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index b18a872836..a3a1969ee7 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -19,6 +19,7 @@ #include "android-base/unique_fd.h" #include "renderengine/DisplaySettings.h" #include "renderengine/LayerSettings.h" +#include "renderengine/impl/ExternalTexture.h" #include "ui/GraphicBuffer.h" #include "ui/GraphicTypes.h" #include "ui/PixelFormat.h" @@ -365,8 +366,8 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { 1, usage, "primeShaderCache_dst"); const auto dstTexture = - std::make_shared<ExternalTexture>(dstBuffer, *renderengine, - ExternalTexture::Usage::WRITEABLE); + std::make_shared<impl::ExternalTexture>(dstBuffer, *renderengine, + impl::ExternalTexture::Usage::WRITEABLE); // This buffer will be the source for the call to drawImageLayers. Draw // something to it as a placeholder for what an app draws. We should draw // something, but the details are not important. Make use of the shadow layer drawing step @@ -375,10 +376,10 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, usage, "drawImageLayer_src"); - const auto srcTexture = - std::make_shared<ExternalTexture>(srcBuffer, *renderengine, - ExternalTexture::Usage::READABLE | - ExternalTexture::Usage::WRITEABLE); + const auto srcTexture = std::make_shared< + impl::ExternalTexture>(srcBuffer, *renderengine, + impl::ExternalTexture::Usage::READABLE | + impl::ExternalTexture::Usage::WRITEABLE); drawHolePunchLayer(renderengine, display, dstTexture); drawSolidLayers(renderengine, display, dstTexture); @@ -398,8 +399,8 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, usageExternal, "primeShaderCache_external"); const auto externalTexture = - std::make_shared<ExternalTexture>(externalBuffer, *renderengine, - ExternalTexture::Usage::READABLE); + std::make_shared<impl::ExternalTexture>(externalBuffer, *renderengine, + impl::ExternalTexture::Usage::READABLE); std::vector<const std::shared_ptr<ExternalTexture>> textures = {srcTexture, externalTexture}; @@ -412,8 +413,8 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { status_t error = f16ExternalBuffer->initCheck(); if (!error) { const auto f16ExternalTexture = - std::make_shared<ExternalTexture>(f16ExternalBuffer, *renderengine, - ExternalTexture::Usage::READABLE); + std::make_shared<impl::ExternalTexture>(f16ExternalBuffer, *renderengine, + impl::ExternalTexture::Usage::READABLE); textures.push_back(f16ExternalTexture); } diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index eb2b2dcbfa..2a25b0bfeb 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -26,6 +26,7 @@ #include <gtest/gtest.h> #include <renderengine/ExternalTexture.h> #include <renderengine/RenderEngine.h> +#include <renderengine/impl/ExternalTexture.h> #include <sync/sync.h> #include <system/graphics-base-v1.0.h> #include <tonemap/tonemap.h> @@ -178,7 +179,7 @@ class RenderEngineTest : public ::testing::TestWithParam<std::shared_ptr<RenderE public: std::shared_ptr<renderengine::ExternalTexture> allocateDefaultBuffer() { return std::make_shared< - renderengine:: + renderengine::impl:: ExternalTexture>(new GraphicBuffer(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT, HAL_PIXEL_FORMAT_RGBA_8888, 1, @@ -188,15 +189,16 @@ public: GRALLOC_USAGE_HW_TEXTURE, "output"), *mRE, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage::WRITEABLE); + renderengine::impl::ExternalTexture::Usage::READABLE | + renderengine::impl::ExternalTexture::Usage:: + WRITEABLE); } // Allocates a 1x1 buffer to fill with a solid color std::shared_ptr<renderengine::ExternalTexture> allocateSourceBuffer(uint32_t width, uint32_t height) { return std::make_shared< - renderengine:: + renderengine::impl:: ExternalTexture>(new GraphicBuffer(width, height, HAL_PIXEL_FORMAT_RGBA_8888, 1, GRALLOC_USAGE_SW_READ_OFTEN | @@ -204,8 +206,9 @@ public: GRALLOC_USAGE_HW_TEXTURE, "input"), *mRE, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage::WRITEABLE); + renderengine::impl::ExternalTexture::Usage::READABLE | + renderengine::impl::ExternalTexture::Usage:: + WRITEABLE); } std::shared_ptr<renderengine::ExternalTexture> allocateAndFillSourceBuffer(uint32_t width, @@ -2439,16 +2442,17 @@ TEST_P(RenderEngineTest, test_tonemapPQMatches) { }; auto buf = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, - HAL_PIXEL_FORMAT_RGBA_8888, 1, - GRALLOC_USAGE_SW_READ_OFTEN | - GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_RENDER | - GRALLOC_USAGE_HW_TEXTURE, - "input"), - *mRE, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage::WRITEABLE); + renderengine::impl:: + ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, + GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_RENDER | + GRALLOC_USAGE_HW_TEXTURE, + "input"), + *mRE, + renderengine::impl::ExternalTexture::Usage::READABLE | + renderengine::impl::ExternalTexture::Usage::WRITEABLE); ASSERT_EQ(0, buf->getBuffer()->initCheck()); { @@ -2472,16 +2476,17 @@ TEST_P(RenderEngineTest, test_tonemapPQMatches) { } mBuffer = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, - HAL_PIXEL_FORMAT_RGBA_8888, 1, - GRALLOC_USAGE_SW_READ_OFTEN | - GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_RENDER | - GRALLOC_USAGE_HW_TEXTURE, - "output"), - *mRE, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage::WRITEABLE); + renderengine::impl:: + ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, + GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_RENDER | + GRALLOC_USAGE_HW_TEXTURE, + "output"), + *mRE, + renderengine::impl::ExternalTexture::Usage::READABLE | + renderengine::impl::ExternalTexture::Usage::WRITEABLE); ASSERT_EQ(0, mBuffer->getBuffer()->initCheck()); const renderengine::LayerSettings layer{ diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp index db7e12b71b..96851892b4 100644 --- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp +++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp @@ -17,6 +17,7 @@ #include <cutils/properties.h> #include <gmock/gmock.h> #include <gtest/gtest.h> +#include <renderengine/impl/ExternalTexture.h> #include <renderengine/mock/RenderEngine.h> #include "../threaded/RenderEngineThreaded.h" @@ -174,9 +175,10 @@ TEST_F(RenderEngineThreadedTest, drawLayers) { renderengine::DisplaySettings settings; std::vector<renderengine::LayerSettings> layers; std::shared_ptr<renderengine::ExternalTexture> buffer = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(), *mRenderEngine, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage::WRITEABLE); + renderengine::impl:: + ExternalTexture>(new GraphicBuffer(), *mRenderEngine, + renderengine::impl::ExternalTexture::Usage::READABLE | + renderengine::impl::ExternalTexture::Usage::WRITEABLE); base::unique_fd bufferFence; diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp index e1560c0740..da88e8541a 100644 --- a/libs/sensor/Sensor.cpp +++ b/libs/sensor/Sensor.cpp @@ -472,7 +472,15 @@ const Sensor::uuid_t& Sensor::getUuid() const { } void Sensor::setId(int32_t id) { - mUuid.i64[0] = id; + mId = id; +} + +int32_t Sensor::getId() const { + return mId; +} + +void Sensor::anonymizeUuid() { + mUuid.i64[0] = mId; mUuid.i64[1] = 0; } @@ -489,17 +497,14 @@ void Sensor::capHighestDirectReportRateLevel(int32_t cappedRateLevel) { } } -int32_t Sensor::getId() const { - return int32_t(mUuid.i64[0]); -} - size_t Sensor::getFlattenedSize() const { size_t fixedSize = sizeof(mVersion) + sizeof(mHandle) + sizeof(mType) + sizeof(mMinValue) + sizeof(mMaxValue) + sizeof(mResolution) + sizeof(mPower) + sizeof(mMinDelay) + sizeof(mFifoMaxEventCount) + sizeof(mFifoMaxEventCount) + sizeof(mRequiredPermissionRuntime) + - sizeof(mRequiredAppOp) + sizeof(mMaxDelay) + sizeof(mFlags) + sizeof(mUuid); + sizeof(mRequiredAppOp) + sizeof(mMaxDelay) + sizeof(mFlags) + + sizeof(mUuid) + sizeof(mId); size_t variableSize = sizeof(uint32_t) + FlattenableUtils::align<4>(mName.length()) + @@ -533,18 +538,8 @@ status_t Sensor::flatten(void* buffer, size_t size) const { FlattenableUtils::write(buffer, size, mRequiredAppOp); FlattenableUtils::write(buffer, size, mMaxDelay); FlattenableUtils::write(buffer, size, mFlags); - if (mUuid.i64[1] != 0) { - // We should never hit this case with our current API, but we - // could via a careless API change. If that happens, - // this code will keep us from leaking our UUID (while probably - // breaking dynamic sensors). See b/29547335. - ALOGW("Sensor with UUID being flattened; sending 0. Expect " - "bad dynamic sensor behavior"); - uuid_t tmpUuid; // default constructor makes this 0. - FlattenableUtils::write(buffer, size, tmpUuid); - } else { - FlattenableUtils::write(buffer, size, mUuid); - } + FlattenableUtils::write(buffer, size, mUuid); + FlattenableUtils::write(buffer, size, mId); return NO_ERROR; } @@ -584,7 +579,7 @@ status_t Sensor::unflatten(void const* buffer, size_t size) { size_t fixedSize2 = sizeof(mRequiredPermissionRuntime) + sizeof(mRequiredAppOp) + sizeof(mMaxDelay) + - sizeof(mFlags) + sizeof(mUuid); + sizeof(mFlags) + sizeof(mUuid) + sizeof(mId); if (size < fixedSize2) { return NO_MEMORY; } @@ -594,6 +589,7 @@ status_t Sensor::unflatten(void const* buffer, size_t size) { FlattenableUtils::read(buffer, size, mMaxDelay); FlattenableUtils::read(buffer, size, mFlags); FlattenableUtils::read(buffer, size, mUuid); + FlattenableUtils::read(buffer, size, mId); return NO_ERROR; } diff --git a/libs/sensor/include/sensor/Sensor.h b/libs/sensor/include/sensor/Sensor.h index 374b68fab5..bae8a1380b 100644 --- a/libs/sensor/include/sensor/Sensor.h +++ b/libs/sensor/include/sensor/Sensor.h @@ -96,11 +96,8 @@ public: bool isDirectChannelTypeSupported(int32_t sharedMemType) const; int32_t getReportingMode() const; - // Note that after setId() has been called, getUuid() no longer - // returns the UUID. - // TODO(b/29547335): Remove getUuid(), add getUuidIndex(), and - // make sure setId() doesn't change the UuidIndex. const uuid_t& getUuid() const; + void anonymizeUuid(); int32_t getId() const; void setId(int32_t id); @@ -132,10 +129,8 @@ private: int32_t mRequiredAppOp; int32_t mMaxDelay; uint32_t mFlags; - // TODO(b/29547335): Get rid of this field and replace with an index. - // The index will be into a separate global vector of UUIDs. - // Also add an mId field (and change flatten/unflatten appropriately). uuid_t mUuid; + int32_t mId; static void flattenString8(void*& buffer, size_t& size, const String8& string8); static bool unflattenString8(void const*& buffer, size_t& size, String8& outputString8); }; diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 006c4780ad..980fc8bcf1 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -29,6 +29,11 @@ license { ], } +cc_library_headers { + name: "libui_fuzzableDataspaces_headers", + export_include_dirs: ["include/ui/fuzzer/"], +} + cc_defaults { name: "libui-defaults", clang: true, diff --git a/libs/ui/include/ui/fuzzer/FuzzableDataspaces.h b/libs/ui/include/ui/fuzzer/FuzzableDataspaces.h new file mode 100644 index 0000000000..4200d6a72d --- /dev/null +++ b/libs/ui/include/ui/fuzzer/FuzzableDataspaces.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <ui/GraphicTypes.h> +using namespace android; + +constexpr ui::Dataspace kDataspaces[] = { + ui::Dataspace::UNKNOWN, + ui::Dataspace::ARBITRARY, + ui::Dataspace::STANDARD_UNSPECIFIED, + ui::Dataspace::STANDARD_BT709, + ui::Dataspace::STANDARD_BT601_625, + ui::Dataspace::STANDARD_BT601_625_UNADJUSTED, + ui::Dataspace::STANDARD_BT601_525, + ui::Dataspace::STANDARD_BT601_525_UNADJUSTED, + ui::Dataspace::STANDARD_BT2020, + ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE, + ui::Dataspace::STANDARD_BT470M, + ui::Dataspace::STANDARD_FILM, + ui::Dataspace::STANDARD_DCI_P3, + ui::Dataspace::STANDARD_ADOBE_RGB, + ui::Dataspace::TRANSFER_UNSPECIFIED, + ui::Dataspace::TRANSFER_LINEAR, + ui::Dataspace::TRANSFER_SRGB, + ui::Dataspace::TRANSFER_SMPTE_170M, + ui::Dataspace::TRANSFER_GAMMA2_2, + ui::Dataspace::TRANSFER_GAMMA2_6, + ui::Dataspace::TRANSFER_GAMMA2_8, + ui::Dataspace::TRANSFER_ST2084, + ui::Dataspace::TRANSFER_HLG, + ui::Dataspace::RANGE_UNSPECIFIED, + ui::Dataspace::RANGE_FULL, + ui::Dataspace::RANGE_LIMITED, + ui::Dataspace::RANGE_EXTENDED, + ui::Dataspace::SRGB_LINEAR, + ui::Dataspace::V0_SRGB_LINEAR, + ui::Dataspace::V0_SCRGB_LINEAR, + ui::Dataspace::SRGB, + ui::Dataspace::V0_SRGB, + ui::Dataspace::V0_SCRGB, + ui::Dataspace::JFIF, + ui::Dataspace::V0_JFIF, + ui::Dataspace::BT601_625, + ui::Dataspace::V0_BT601_625, + ui::Dataspace::BT601_525, + ui::Dataspace::V0_BT601_525, + ui::Dataspace::BT709, + ui::Dataspace::V0_BT709, + ui::Dataspace::DCI_P3_LINEAR, + ui::Dataspace::DCI_P3, + ui::Dataspace::DISPLAY_P3_LINEAR, + ui::Dataspace::DISPLAY_P3, + ui::Dataspace::ADOBE_RGB, + ui::Dataspace::BT2020_LINEAR, + ui::Dataspace::BT2020, + ui::Dataspace::BT2020_PQ, + ui::Dataspace::DEPTH, + ui::Dataspace::SENSOR, + ui::Dataspace::BT2020_ITU, + ui::Dataspace::BT2020_ITU_PQ, + ui::Dataspace::BT2020_ITU_HLG, + ui::Dataspace::BT2020_HLG, + ui::Dataspace::DISPLAY_BT2020, + ui::Dataspace::DYNAMIC_DEPTH, + ui::Dataspace::JPEG_APP_SEGMENTS, + ui::Dataspace::HEIF, +}; diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp index b9b6a19606..5b4ee21b42 100644 --- a/services/gpuservice/Android.bp +++ b/services/gpuservice/Android.bp @@ -31,6 +31,7 @@ cc_defaults { "libcutils", "libgfxstats", "libgpumem", + "libgpuwork", "libgpumemtracer", "libgraphicsenv", "liblog", diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index 52d5d4fc46..7b9782f4e8 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -25,6 +25,7 @@ #include <binder/PermissionCache.h> #include <cutils/properties.h> #include <gpumem/GpuMem.h> +#include <gpuwork/GpuWork.h> #include <gpustats/GpuStats.h> #include <private/android_filesystem_config.h> #include <tracing/GpuMemTracer.h> @@ -50,13 +51,20 @@ const char* const GpuService::SERVICE_NAME = "gpu"; GpuService::GpuService() : mGpuMem(std::make_shared<GpuMem>()), + mGpuWork(std::make_shared<gpuwork::GpuWork>()), mGpuStats(std::make_unique<GpuStats>()), mGpuMemTracer(std::make_unique<GpuMemTracer>()) { - std::thread asyncInitThread([this]() { + + std::thread gpuMemAsyncInitThread([this]() { mGpuMem->initialize(); mGpuMemTracer->initialize(mGpuMem); }); - asyncInitThread.detach(); + gpuMemAsyncInitThread.detach(); + + std::thread gpuWorkAsyncInitThread([this]() { + mGpuWork->initialize(); + }); + gpuWorkAsyncInitThread.detach(); }; void GpuService::setGpuStats(const std::string& driverPackageName, @@ -124,6 +132,7 @@ status_t GpuService::doDump(int fd, const Vector<String16>& args, bool /*asProto bool dumpDriverInfo = false; bool dumpMem = false; bool dumpStats = false; + bool dumpWork = false; size_t numArgs = args.size(); if (numArgs) { @@ -134,9 +143,11 @@ status_t GpuService::doDump(int fd, const Vector<String16>& args, bool /*asProto dumpDriverInfo = true; } else if (args[index] == String16("--gpumem")) { dumpMem = true; + } else if (args[index] == String16("--gpuwork")) { + dumpWork = true; } } - dumpAll = !(dumpDriverInfo || dumpMem || dumpStats); + dumpAll = !(dumpDriverInfo || dumpMem || dumpStats || dumpWork); } if (dumpAll || dumpDriverInfo) { @@ -151,6 +162,10 @@ status_t GpuService::doDump(int fd, const Vector<String16>& args, bool /*asProto mGpuStats->dump(args, &result); result.append("\n"); } + if (dumpAll || dumpWork) { + mGpuWork->dump(args, &result); + result.append("\n"); + } } write(fd, result.c_str(), result.size()); diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h index 409084b656..d7313d165e 100644 --- a/services/gpuservice/GpuService.h +++ b/services/gpuservice/GpuService.h @@ -28,6 +28,10 @@ namespace android { +namespace gpuwork { +class GpuWork; +} + class GpuMem; class GpuStats; class GpuMemTracer; @@ -77,6 +81,7 @@ private: * Attributes */ std::shared_ptr<GpuMem> mGpuMem; + std::shared_ptr<gpuwork::GpuWork> mGpuWork; std::unique_ptr<GpuStats> mGpuStats; std::unique_ptr<GpuMemTracer> mGpuMemTracer; std::mutex mLock; diff --git a/services/gpuservice/gpuwork/Android.bp b/services/gpuservice/gpuwork/Android.bp new file mode 100644 index 0000000000..89b31a6884 --- /dev/null +++ b/services/gpuservice/gpuwork/Android.bp @@ -0,0 +1,61 @@ +// Copyright 2022 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + default_applicable_licenses: ["frameworks_native_license"], +} + +cc_library_shared { + name: "libgpuwork", + srcs: [ + "GpuWork.cpp", + ], + header_libs: [ + "gpu_work_structs", + ], + shared_libs: [ + "libbase", + "libbinder", + "libbpf_bcc", + "libbpf_android", + "libcutils", + "liblog", + "libstatslog", + "libstatspull", + "libutils", + ], + export_include_dirs: [ + "include", + ], + export_header_lib_headers: [ + "gpu_work_structs", + ], + export_shared_lib_headers: [ + "libbase", + "libbpf_android", + "libstatspull", + ], + cppflags: [ + "-Wall", + "-Werror", + "-Wformat", + "-Wthread-safety", + "-Wunused", + "-Wunreachable-code", + ], + required: [ + "bpfloader", + "gpu_work.o", + ], +} diff --git a/services/gpuservice/gpuwork/GpuWork.cpp b/services/gpuservice/gpuwork/GpuWork.cpp new file mode 100644 index 0000000000..e7b1cd4006 --- /dev/null +++ b/services/gpuservice/gpuwork/GpuWork.cpp @@ -0,0 +1,504 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef LOG_TAG +#define LOG_TAG "GpuWork" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include "gpuwork/GpuWork.h" + +#include <android-base/stringprintf.h> +#include <binder/PermissionCache.h> +#include <bpf/WaitForProgsLoaded.h> +#include <libbpf.h> +#include <libbpf_android.h> +#include <log/log.h> +#include <random> +#include <stats_event.h> +#include <statslog.h> +#include <unistd.h> +#include <utils/Timers.h> +#include <utils/Trace.h> + +#include <bit> +#include <chrono> +#include <cstdint> +#include <limits> +#include <map> +#include <mutex> +#include <unordered_map> +#include <vector> + +#include "gpuwork/gpu_work.h" + +#define MS_IN_NS (1000000) + +namespace android { +namespace gpuwork { + +namespace { + +// Gets a BPF map from |mapPath|. +template <class Key, class Value> +bool getBpfMap(const char* mapPath, bpf::BpfMap<Key, Value>* out) { + errno = 0; + auto map = bpf::BpfMap<Key, Value>(mapPath); + if (!map.isValid()) { + ALOGW("Failed to create bpf map from %s [%d(%s)]", mapPath, errno, strerror(errno)); + return false; + } + *out = std::move(map); + return true; +} + +template <typename SourceType> +inline int32_t cast_int32(SourceType) = delete; + +template <typename SourceType> +inline int32_t bitcast_int32(SourceType) = delete; + +template <> +inline int32_t bitcast_int32<uint32_t>(uint32_t source) { + int32_t result; + memcpy(&result, &source, sizeof(result)); + return result; +} + +template <> +inline int32_t cast_int32<uint64_t>(uint64_t source) { + if (source > std::numeric_limits<int32_t>::max()) { + return std::numeric_limits<int32_t>::max(); + } + return static_cast<int32_t>(source); +} + +template <> +inline int32_t cast_int32<long long>(long long source) { + if (source > std::numeric_limits<int32_t>::max()) { + return std::numeric_limits<int32_t>::max(); + } else if (source < std::numeric_limits<int32_t>::min()) { + return std::numeric_limits<int32_t>::min(); + } + return static_cast<int32_t>(source); +} + +} // namespace + +using base::StringAppendF; + +GpuWork::~GpuWork() { + // If we created our clearer thread, then we must stop it and join it. + if (mMapClearerThread.joinable()) { + // Tell the thread to terminate. + { + std::scoped_lock<std::mutex> lock(mMutex); + mIsTerminating = true; + mIsTerminatingConditionVariable.notify_all(); + } + + // Now, we can join it. + mMapClearerThread.join(); + } + + { + std::scoped_lock<std::mutex> lock(mMutex); + if (mStatsdRegistered) { + AStatsManager_clearPullAtomCallback(android::util::GPU_FREQ_TIME_IN_STATE_PER_UID); + } + } + + bpf_detach_tracepoint("power", "gpu_work_period"); +} + +void GpuWork::initialize() { + // Make sure BPF programs are loaded. + bpf::waitForProgsLoaded(); + + waitForPermissions(); + + // Get the BPF maps before trying to attach the BPF program; if we can't get + // the maps then there is no point in attaching the BPF program. + { + std::lock_guard<std::mutex> lock(mMutex); + + if (!getBpfMap("/sys/fs/bpf/map_gpu_work_gpu_work_map", &mGpuWorkMap)) { + return; + } + + if (!getBpfMap("/sys/fs/bpf/map_gpu_work_gpu_work_global_data", &mGpuWorkGlobalDataMap)) { + return; + } + + mPreviousMapClearTimePoint = std::chrono::steady_clock::now(); + } + + // Attach the tracepoint ONLY if we got the map above. + if (!attachTracepoint("/sys/fs/bpf/prog_gpu_work_tracepoint_power_gpu_work_period", "power", + "gpu_work_period")) { + return; + } + + // Create the map clearer thread, and store it to |mMapClearerThread|. + std::thread thread([this]() { periodicallyClearMap(); }); + + mMapClearerThread.swap(thread); + + { + std::lock_guard<std::mutex> lock(mMutex); + AStatsManager_setPullAtomCallback(int32_t{android::util::GPU_FREQ_TIME_IN_STATE_PER_UID}, + nullptr, GpuWork::pullAtomCallback, this); + mStatsdRegistered = true; + } + + ALOGI("Initialized!"); + + mInitialized.store(true); +} + +void GpuWork::dump(const Vector<String16>& /* args */, std::string* result) { + if (!mInitialized.load()) { + result->append("GPU time in state information is not available.\n"); + return; + } + + // Ordered map ensures output data is sorted by UID. + std::map<Uid, UidTrackingInfo> dumpMap; + + { + std::lock_guard<std::mutex> lock(mMutex); + + if (!mGpuWorkMap.isValid()) { + result->append("GPU time in state map is not available.\n"); + return; + } + + // Iteration of BPF hash maps can be unreliable (no data races, but elements + // may be repeated), as the map is typically being modified by other + // threads. The buckets are all preallocated. Our eBPF program only updates + // entries (in-place) or adds entries. |GpuWork| only iterates or clears the + // map while holding |mMutex|. Given this, we should be able to iterate over + // all elements reliably. In the worst case, we might see elements more than + // once. + + // Note that userspace reads of BPF maps make a copy of the value, and + // thus the returned value is not being concurrently accessed by the BPF + // program (no atomic reads needed below). + + mGpuWorkMap.iterateWithValue([&dumpMap](const Uid& key, const UidTrackingInfo& value, + const android::bpf::BpfMap<Uid, UidTrackingInfo>&) + -> base::Result<void> { + dumpMap[key] = value; + return {}; + }); + } + + // Find the largest frequency where some UID has spent time in that frequency. + size_t largestFrequencyWithTime = 0; + for (const auto& uidToUidInfo : dumpMap) { + for (size_t i = largestFrequencyWithTime + 1; i < kNumTrackedFrequencies; ++i) { + if (uidToUidInfo.second.frequency_times_ns[i] > 0) { + largestFrequencyWithTime = i; + } + } + } + + // Dump time in state information. + // E.g. + // uid/freq: 0MHz 50MHz 100MHz ... + // 1000: 0 0 0 0 ... + // 1003: 0 0 3456 0 ... + // [errors:3]1006: 0 0 3456 0 ... + + // Header. + result->append("GPU time in frequency state in ms.\n"); + result->append("uid/freq: 0MHz"); + for (size_t i = 1; i <= largestFrequencyWithTime; ++i) { + StringAppendF(result, " %zuMHz", i * 50); + } + result->append("\n"); + + for (const auto& uidToUidInfo : dumpMap) { + if (uidToUidInfo.second.error_count) { + StringAppendF(result, "[errors:%" PRIu32 "]", uidToUidInfo.second.error_count); + } + StringAppendF(result, "%" PRIu32 ":", uidToUidInfo.first); + for (size_t i = 0; i <= largestFrequencyWithTime; ++i) { + StringAppendF(result, " %" PRIu64, + uidToUidInfo.second.frequency_times_ns[i] / MS_IN_NS); + } + result->append("\n"); + } +} + +bool GpuWork::attachTracepoint(const char* programPath, const char* tracepointGroup, + const char* tracepointName) { + errno = 0; + base::unique_fd fd(bpf::retrieveProgram(programPath)); + if (fd < 0) { + ALOGW("Failed to retrieve pinned program from %s [%d(%s)]", programPath, errno, + strerror(errno)); + return false; + } + + // Attach the program to the tracepoint. The tracepoint is automatically enabled. + errno = 0; + int count = 0; + while (bpf_attach_tracepoint(fd.get(), tracepointGroup, tracepointName) < 0) { + if (++count > kGpuWaitTimeoutSeconds) { + ALOGW("Failed to attach bpf program to %s/%s tracepoint [%d(%s)]", tracepointGroup, + tracepointName, errno, strerror(errno)); + return false; + } + // Retry until GPU driver loaded or timeout. + sleep(1); + errno = 0; + } + + return true; +} + +AStatsManager_PullAtomCallbackReturn GpuWork::pullAtomCallback(int32_t atomTag, + AStatsEventList* data, + void* cookie) { + ATRACE_CALL(); + + GpuWork* gpuWork = reinterpret_cast<GpuWork*>(cookie); + if (atomTag == android::util::GPU_FREQ_TIME_IN_STATE_PER_UID) { + return gpuWork->pullFrequencyAtoms(data); + } + + return AStatsManager_PULL_SKIP; +} + +AStatsManager_PullAtomCallbackReturn GpuWork::pullFrequencyAtoms(AStatsEventList* data) { + ATRACE_CALL(); + + if (!data || !mInitialized.load()) { + return AStatsManager_PULL_SKIP; + } + + std::lock_guard<std::mutex> lock(mMutex); + + if (!mGpuWorkMap.isValid()) { + return AStatsManager_PULL_SKIP; + } + + std::unordered_map<Uid, UidTrackingInfo> uidInfos; + + // Iteration of BPF hash maps can be unreliable (no data races, but elements + // may be repeated), as the map is typically being modified by other + // threads. The buckets are all preallocated. Our eBPF program only updates + // entries (in-place) or adds entries. |GpuWork| only iterates or clears the + // map while holding |mMutex|. Given this, we should be able to iterate over + // all elements reliably. In the worst case, we might see elements more than + // once. + + // Note that userspace reads of BPF maps make a copy of the value, and thus + // the returned value is not being concurrently accessed by the BPF program + // (no atomic reads needed below). + + mGpuWorkMap.iterateWithValue( + [&uidInfos](const Uid& key, const UidTrackingInfo& value, + const android::bpf::BpfMap<Uid, UidTrackingInfo>&) -> base::Result<void> { + uidInfos[key] = value; + return {}; + }); + + ALOGI("pullFrequencyAtoms: uidInfos.size() == %zu", uidInfos.size()); + + // Get a list of just the UIDs; the order does not matter. + std::vector<Uid> uids; + for (const auto& pair : uidInfos) { + uids.push_back(pair.first); + } + + std::random_device device; + std::default_random_engine random_engine(device()); + + // If we have more than |kNumSampledUids| UIDs, choose |kNumSampledUids| + // random UIDs. We swap them to the front of the list. Given the list + // indices 0..i..n-1, we have the following inclusive-inclusive ranges: + // - [0, i-1] == the randomly chosen elements. + // - [i, n-1] == the remaining unchosen elements. + if (uids.size() > kNumSampledUids) { + for (size_t i = 0; i < kNumSampledUids; ++i) { + std::uniform_int_distribution<size_t> uniform_dist(i, uids.size() - 1); + size_t random_index = uniform_dist(random_engine); + std::swap(uids[i], uids[random_index]); + } + // Only keep the front |kNumSampledUids| elements. + uids.resize(kNumSampledUids); + } + + ALOGI("pullFrequencyAtoms: uids.size() == %zu", uids.size()); + + auto now = std::chrono::steady_clock::now(); + + int32_t duration = cast_int32( + std::chrono::duration_cast<std::chrono::seconds>(now - mPreviousMapClearTimePoint) + .count()); + + for (const Uid uid : uids) { + const UidTrackingInfo& info = uidInfos[uid]; + ALOGI("pullFrequencyAtoms: adding stats for UID %" PRIu32, uid); + android::util::addAStatsEvent(data, int32_t{android::util::GPU_FREQ_TIME_IN_STATE_PER_UID}, + // uid + bitcast_int32(uid), + // time_duration_seconds + int32_t{duration}, + // max_freq_mhz + int32_t{1000}, + // freq_0_mhz_time_millis + cast_int32(info.frequency_times_ns[0] / 1000000), + // freq_50_mhz_time_millis + cast_int32(info.frequency_times_ns[1] / 1000000), + // ... etc. ... + cast_int32(info.frequency_times_ns[2] / 1000000), + cast_int32(info.frequency_times_ns[3] / 1000000), + cast_int32(info.frequency_times_ns[4] / 1000000), + cast_int32(info.frequency_times_ns[5] / 1000000), + cast_int32(info.frequency_times_ns[6] / 1000000), + cast_int32(info.frequency_times_ns[7] / 1000000), + cast_int32(info.frequency_times_ns[8] / 1000000), + cast_int32(info.frequency_times_ns[9] / 1000000), + cast_int32(info.frequency_times_ns[10] / 1000000), + cast_int32(info.frequency_times_ns[11] / 1000000), + cast_int32(info.frequency_times_ns[12] / 1000000), + cast_int32(info.frequency_times_ns[13] / 1000000), + cast_int32(info.frequency_times_ns[14] / 1000000), + cast_int32(info.frequency_times_ns[15] / 1000000), + cast_int32(info.frequency_times_ns[16] / 1000000), + cast_int32(info.frequency_times_ns[17] / 1000000), + cast_int32(info.frequency_times_ns[18] / 1000000), + cast_int32(info.frequency_times_ns[19] / 1000000), + // freq_1000_mhz_time_millis + cast_int32(info.frequency_times_ns[20] / 1000000)); + } + clearMap(); + return AStatsManager_PULL_SUCCESS; +} + +void GpuWork::periodicallyClearMap() { + std::unique_lock<std::mutex> lock(mMutex); + + auto previousTime = std::chrono::steady_clock::now(); + + while (true) { + if (mIsTerminating) { + break; + } + auto nextTime = std::chrono::steady_clock::now(); + auto differenceSeconds = + std::chrono::duration_cast<std::chrono::seconds>(nextTime - previousTime); + if (differenceSeconds.count() > kMapClearerWaitDurationSeconds) { + // It has been >1 hour, so clear the map, if needed. + clearMapIfNeeded(); + // We only update |previousTime| if we actually checked the map. + previousTime = nextTime; + } + // Sleep for ~1 hour. It does not matter if we don't check the map for 2 + // hours. + mIsTerminatingConditionVariable.wait_for(lock, + std::chrono::seconds{ + kMapClearerWaitDurationSeconds}); + } +} + +void GpuWork::clearMapIfNeeded() { + if (!mInitialized.load() || !mGpuWorkMap.isValid() || !mGpuWorkGlobalDataMap.isValid()) { + ALOGW("Map clearing could not occur because we are not initialized properly"); + return; + } + + base::Result<GlobalData> globalData = mGpuWorkGlobalDataMap.readValue(0); + if (!globalData.ok()) { + ALOGW("Could not read BPF global data map entry"); + return; + } + + // Note that userspace reads of BPF maps make a copy of the value, and thus + // the return value is not being concurrently accessed by the BPF program + // (no atomic reads needed below). + + uint64_t numEntries = globalData.value().num_map_entries; + + // If the map is <=75% full, we do nothing. + if (numEntries <= (kMaxTrackedUids / 4) * 3) { + return; + } + + clearMap(); +} + +void GpuWork::clearMap() { + if (!mInitialized.load() || !mGpuWorkMap.isValid() || !mGpuWorkGlobalDataMap.isValid()) { + ALOGW("Map clearing could not occur because we are not initialized properly"); + return; + } + + base::Result<GlobalData> globalData = mGpuWorkGlobalDataMap.readValue(0); + if (!globalData.ok()) { + ALOGW("Could not read BPF global data map entry"); + return; + } + + // Iterating BPF maps to delete keys is tricky. If we just repeatedly call + // |getFirstKey()| and delete that, we may loop forever (or for a long time) + // because our BPF program might be repeatedly re-adding UID keys. Also, + // even if we limit the number of elements we try to delete, we might only + // delete new entries, leaving old entries in the map. If we delete a key A + // and then call |getNextKey(A)|, the first key in the map is returned, so + // we have the same issue. + // + // Thus, we instead get the next key and then delete the previous key. We + // also limit the number of deletions we try, just in case. + + base::Result<Uid> key = mGpuWorkMap.getFirstKey(); + + for (size_t i = 0; i < kMaxTrackedUids; ++i) { + if (!key.ok()) { + break; + } + base::Result<Uid> previousKey = key; + key = mGpuWorkMap.getNextKey(previousKey.value()); + mGpuWorkMap.deleteValue(previousKey.value()); + } + + // Reset our counter; |globalData| is a copy of the data, so we have to use + // |writeValue|. + globalData.value().num_map_entries = 0; + mGpuWorkGlobalDataMap.writeValue(0, globalData.value(), BPF_ANY); + + // Update |mPreviousMapClearTimePoint| so we know when we started collecting + // the stats. + mPreviousMapClearTimePoint = std::chrono::steady_clock::now(); +} + +void GpuWork::waitForPermissions() { + const String16 permissionRegisterStatsPullAtom(kPermissionRegisterStatsPullAtom); + int count = 0; + while (!PermissionCache::checkPermission(permissionRegisterStatsPullAtom, getpid(), getuid())) { + if (++count > kPermissionsWaitTimeoutSeconds) { + ALOGW("Timed out waiting for android.permission.REGISTER_STATS_PULL_ATOM"); + return; + } + // Retry. + sleep(1); + } +} + +} // namespace gpuwork +} // namespace android diff --git a/services/gpuservice/gpuwork/bpfprogs/Android.bp b/services/gpuservice/gpuwork/bpfprogs/Android.bp new file mode 100644 index 0000000000..b3c4eff847 --- /dev/null +++ b/services/gpuservice/gpuwork/bpfprogs/Android.bp @@ -0,0 +1,35 @@ +// Copyright 2022 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + default_applicable_licenses: ["frameworks_native_license"], +} + +bpf { + name: "gpu_work.o", + srcs: ["gpu_work.c"], + cflags: [ + "-Wall", + "-Werror", + "-Wformat", + "-Wthread-safety", + "-Wunused", + "-Wunreachable-code", + ], +} + +cc_library_headers { + name: "gpu_work_structs", + export_include_dirs: ["include"], +} diff --git a/services/gpuservice/gpuwork/bpfprogs/gpu_work.c b/services/gpuservice/gpuwork/bpfprogs/gpu_work.c new file mode 100644 index 0000000000..a0e1b22540 --- /dev/null +++ b/services/gpuservice/gpuwork/bpfprogs/gpu_work.c @@ -0,0 +1,219 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/gpuwork/gpu_work.h" + +#include <linux/bpf.h> +#include <stddef.h> +#include <stdint.h> + +#ifdef MOCK_BPF +#include <test/mock_bpf_helpers.h> +#else +#include <bpf_helpers.h> +#endif + +#define S_IN_NS (1000000000) +#define MHZ_IN_KHZS (1000) + +typedef uint32_t Uid; + +// A map from UID to |UidTrackingInfo|. +DEFINE_BPF_MAP_GRW(gpu_work_map, HASH, Uid, UidTrackingInfo, kMaxTrackedUids, AID_GRAPHICS); + +// A map containing a single entry of |GlobalData|. +DEFINE_BPF_MAP_GRW(gpu_work_global_data, ARRAY, uint32_t, GlobalData, 1, AID_GRAPHICS); + +// GpuUidWorkPeriodEvent defines the structure of a kernel tracepoint under the +// tracepoint system (also referred to as the group) "power" and name +// "gpu_work_period". In summary, the kernel tracepoint should be +// "power/gpu_work_period", available at: +// +// /sys/kernel/tracing/events/power/gpu_work_period/ +// +// GpuUidWorkPeriodEvent defines a non-overlapping, non-zero period of time when +// work was running on the GPU for a given application (identified by its UID; +// the persistent, unique ID of the application) from |start_time_ns| to +// |end_time_ns|. Drivers should issue this tracepoint as soon as possible +// (within 1 second) after |end_time_ns|. For a given UID, periods must not +// overlap, but periods from different UIDs can overlap (and should overlap, if +// and only if that is how the work was executed). The period includes +// information such as |frequency_khz|, the frequency that the GPU was running +// at during the period, and |includes_compute_work|, whether the work included +// compute shader work (not just graphics work). GPUs may have multiple +// frequencies that can be adjusted, but the driver should report the frequency +// that most closely estimates power usage (e.g. the frequency of shader cores, +// not a scheduling unit). +// +// If any information changes while work from the UID is running on the GPU +// (e.g. the GPU frequency changes, or the work starts/stops including compute +// work) then the driver must conceptually end the period, issue the tracepoint, +// start tracking a new period, and eventually issue a second tracepoint when +// the work completes or when the information changes again. In this case, the +// |end_time_ns| of the first period must equal the |start_time_ns| of the +// second period. The driver may also end and start a new period (without a +// gap), even if no information changes. For example, this might be convenient +// if there is a collection of work from a UID running on the GPU for a long +// time; ending and starting a period as individual parts of the work complete +// allows the consumer of the tracepoint to be updated about the ongoing work. +// +// For a given UID, the tracepoints must be emitted in order; that is, the +// |start_time_ns| of each subsequent tracepoint for a given UID must be +// monotonically increasing. +typedef struct { + // Actual fields start at offset 8. + uint64_t reserved; + + // The UID of the process (i.e. persistent, unique ID of the Android app) + // that submitted work to the GPU. + uint32_t uid; + + // The GPU frequency during the period. GPUs may have multiple frequencies + // that can be adjusted, but the driver should report the frequency that + // would most closely estimate power usage (e.g. the frequency of shader + // cores, not a scheduling unit). + uint32_t frequency_khz; + + // The start time of the period in nanoseconds. The clock must be + // CLOCK_MONOTONIC, as returned by the ktime_get_ns(void) function. + uint64_t start_time_ns; + + // The end time of the period in nanoseconds. The clock must be + // CLOCK_MONOTONIC, as returned by the ktime_get_ns(void) function. + uint64_t end_time_ns; + + // Flags about the work. Reserved for future use. + uint64_t flags; + + // The maximum GPU frequency allowed during the period according to the + // thermal throttling policy. Must be 0 if no thermal throttling was + // enforced during the period. The value must relate to |frequency_khz|; in + // other words, if |frequency_khz| is the frequency of the GPU shader cores, + // then |thermally_throttled_max_frequency_khz| must be the maximum allowed + // frequency of the GPU shader cores (not the maximum allowed frequency of + // some other part of the GPU). + // + // Note: Unlike with other fields of this struct, if the + // |thermally_throttled_max_frequency_khz| value conceptually changes while + // work from a UID is running on the GPU then the GPU driver does NOT need + // to accurately report this by ending the period and starting to track a + // new period; instead, the GPU driver may report any one of the + // |thermally_throttled_max_frequency_khz| values that was enforced during + // the period. The motivation for this relaxation is that we assume the + // maximum frequency will not be changing rapidly, and so capturing the + // exact point at which the change occurs is unnecessary. + uint32_t thermally_throttled_max_frequency_khz; + +} GpuUidWorkPeriodEvent; + +_Static_assert(offsetof(GpuUidWorkPeriodEvent, uid) == 8 && + offsetof(GpuUidWorkPeriodEvent, frequency_khz) == 12 && + offsetof(GpuUidWorkPeriodEvent, start_time_ns) == 16 && + offsetof(GpuUidWorkPeriodEvent, end_time_ns) == 24 && + offsetof(GpuUidWorkPeriodEvent, flags) == 32 && + offsetof(GpuUidWorkPeriodEvent, thermally_throttled_max_frequency_khz) == 40, + "Field offsets of struct GpuUidWorkPeriodEvent must not be changed because they " + "must match the tracepoint field offsets found via adb shell cat " + "/sys/kernel/tracing/events/power/gpu_work_period/format"); + +DEFINE_BPF_PROG("tracepoint/power/gpu_work_period", AID_ROOT, AID_GRAPHICS, tp_gpu_work_period) +(GpuUidWorkPeriodEvent* const args) { + // Note: In BPF programs, |__sync_fetch_and_add| is translated to an atomic + // add. + + const uint32_t uid = args->uid; + + // Get |UidTrackingInfo| for |uid|. + UidTrackingInfo* uid_tracking_info = bpf_gpu_work_map_lookup_elem(&uid); + if (!uid_tracking_info) { + // There was no existing entry, so we add a new one. + UidTrackingInfo initial_info; + __builtin_memset(&initial_info, 0, sizeof(initial_info)); + if (0 == bpf_gpu_work_map_update_elem(&uid, &initial_info, BPF_NOEXIST)) { + // We added an entry to the map, so we increment our entry counter in + // |GlobalData|. + const uint32_t zero = 0; + // Get the |GlobalData|. + GlobalData* global_data = bpf_gpu_work_global_data_lookup_elem(&zero); + // Getting the global data never fails because it is an |ARRAY| map, + // but we need to keep the verifier happy. + if (global_data) { + __sync_fetch_and_add(&global_data->num_map_entries, 1); + } + } + uid_tracking_info = bpf_gpu_work_map_lookup_elem(&uid); + if (!uid_tracking_info) { + // This should never happen, unless entries are getting deleted at + // this moment. If so, we just give up. + return 0; + } + } + + // The period duration must be non-zero. + if (args->start_time_ns >= args->end_time_ns) { + __sync_fetch_and_add(&uid_tracking_info->error_count, 1); + return 0; + } + + // The frequency must not be 0. + if (args->frequency_khz == 0) { + __sync_fetch_and_add(&uid_tracking_info->error_count, 1); + return 0; + } + + // Calculate the frequency index: see |UidTrackingInfo.frequency_times_ns|. + // Round to the nearest 50MHz bucket. + uint32_t frequency_index = + ((args->frequency_khz / MHZ_IN_KHZS) + (kFrequencyGranularityMhz / 2)) / + kFrequencyGranularityMhz; + if (frequency_index >= kNumTrackedFrequencies) { + frequency_index = kNumTrackedFrequencies - 1; + } + + // Never round down to 0MHz, as this is a special bucket (see below) and not + // an actual operating point. + if (frequency_index == 0) { + frequency_index = 1; + } + + // Update time in state. + __sync_fetch_and_add(&uid_tracking_info->frequency_times_ns[frequency_index], + args->end_time_ns - args->start_time_ns); + + if (uid_tracking_info->previous_end_time_ns > args->start_time_ns) { + // This must not happen because per-UID periods must not overlap and + // must be emitted in order. + __sync_fetch_and_add(&uid_tracking_info->error_count, 1); + } else { + // The period appears to have been emitted after the previous, as + // expected, so we can calculate the gap between this and the previous + // period. + const uint64_t gap_time = args->start_time_ns - uid_tracking_info->previous_end_time_ns; + + // Update |previous_end_time_ns|. + uid_tracking_info->previous_end_time_ns = args->end_time_ns; + + // Update the special 0MHz frequency time, which stores the gaps between + // periods, but only if the gap is < 1 second. + if (gap_time > 0 && gap_time < S_IN_NS) { + __sync_fetch_and_add(&uid_tracking_info->frequency_times_ns[0], gap_time); + } + } + + return 0; +} + +LICENSE("Apache 2.0"); diff --git a/services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpu_work.h b/services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpu_work.h new file mode 100644 index 0000000000..4fe84649a0 --- /dev/null +++ b/services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpu_work.h @@ -0,0 +1,61 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <stdint.h> + +#ifdef __cplusplus +#include <type_traits> + +namespace android { +namespace gpuwork { +#endif + +typedef struct { + // The end time of the previous period from this UID in nanoseconds. + uint64_t previous_end_time_ns; + + // The time spent at each GPU frequency while running GPU work from the UID, + // in nanoseconds. Array index i stores the time for frequency i*50 MHz. So + // index 0 is 0Mhz, index 1 is 50MHz, index 2 is 100MHz, etc., up to index + // |kNumTrackedFrequencies|. + uint64_t frequency_times_ns[21]; + + // The number of times we received |GpuUidWorkPeriodEvent| events in an + // unexpected order. See |GpuUidWorkPeriodEvent|. + uint32_t error_count; + +} UidTrackingInfo; + +typedef struct { + // We cannot query the number of entries in BPF map |gpu_work_map|. We track + // the number of entries (approximately) using a counter so we can check if + // the map is nearly full. + uint64_t num_map_entries; +} GlobalData; + +static const uint32_t kMaxTrackedUids = 512; +static const uint32_t kFrequencyGranularityMhz = 50; +static const uint32_t kNumTrackedFrequencies = 21; + +#ifdef __cplusplus +static_assert(kNumTrackedFrequencies == + std::extent<decltype(UidTrackingInfo::frequency_times_ns)>::value); + +} // namespace gpuwork +} // namespace android +#endif diff --git a/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h new file mode 100644 index 0000000000..b6f493d557 --- /dev/null +++ b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h @@ -0,0 +1,127 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <bpf/BpfMap.h> +#include <stats_pull_atom_callback.h> +#include <utils/Mutex.h> +#include <utils/String16.h> +#include <utils/Vector.h> + +#include <condition_variable> +#include <cstdint> +#include <functional> +#include <thread> + +#include "gpuwork/gpu_work.h" + +namespace android { +namespace gpuwork { + +class GpuWork { +public: + using Uid = uint32_t; + + GpuWork() = default; + ~GpuWork(); + + void initialize(); + + // Dumps the GPU time in frequency state information. + void dump(const Vector<String16>& args, std::string* result); + +private: + // Attaches tracepoint |tracepoint_group|/|tracepoint_name| to BPF program at path + // |program_path|. The tracepoint is also enabled. + static bool attachTracepoint(const char* program_path, const char* tracepoint_group, + const char* tracepoint_name); + + // Native atom puller callback registered in statsd. + static AStatsManager_PullAtomCallbackReturn pullAtomCallback(int32_t atomTag, + AStatsEventList* data, + void* cookie); + + AStatsManager_PullAtomCallbackReturn pullFrequencyAtoms(AStatsEventList* data); + + // Periodically calls |clearMapIfNeeded| to clear the |mGpuWorkMap| map, if + // needed. + // + // Thread safety analysis is skipped because we need to use + // |std::unique_lock|, which is not currently supported by thread safety + // analysis. + void periodicallyClearMap() NO_THREAD_SAFETY_ANALYSIS; + + // Checks whether the |mGpuWorkMap| map is nearly full and, if so, clears + // it. + void clearMapIfNeeded() REQUIRES(mMutex); + + // Clears the |mGpuWorkMap| map. + void clearMap() REQUIRES(mMutex); + + // Waits for required permissions to become set. This seems to be needed + // because platform service permissions might not be set when a service + // first starts. See b/214085769. + void waitForPermissions(); + + // Indicates whether our eBPF components have been initialized. + std::atomic<bool> mInitialized = false; + + // A thread that periodically checks whether |mGpuWorkMap| is nearly full + // and, if so, clears it. + std::thread mMapClearerThread; + + // Mutex for |mGpuWorkMap| and a few other fields. + std::mutex mMutex; + + // BPF map for per-UID GPU work. + bpf::BpfMap<Uid, UidTrackingInfo> mGpuWorkMap GUARDED_BY(mMutex); + + // BPF map containing a single element for global data. + bpf::BpfMap<uint32_t, GlobalData> mGpuWorkGlobalDataMap GUARDED_BY(mMutex); + + // When true, we are being destructed, so |mMapClearerThread| should stop. + bool mIsTerminating GUARDED_BY(mMutex); + + // A condition variable for |mIsTerminating|. + std::condition_variable mIsTerminatingConditionVariable GUARDED_BY(mMutex); + + // 30 second timeout for trying to attach a BPF program to a tracepoint. + static constexpr int kGpuWaitTimeoutSeconds = 30; + + // The wait duration for the map clearer thread; the thread checks the map + // every ~1 hour. + static constexpr uint32_t kMapClearerWaitDurationSeconds = 60 * 60; + + // Whether our |pullAtomCallback| function is registered. + bool mStatsdRegistered GUARDED_BY(mMutex) = false; + + // The number of randomly chosen (i.e. sampled) UIDs to log stats for. + static constexpr int kNumSampledUids = 10; + + // The previous time point at which |mGpuWorkMap| was cleared. + std::chrono::steady_clock::time_point mPreviousMapClearTimePoint GUARDED_BY(mMutex); + + // Permission to register a statsd puller. + static constexpr char16_t kPermissionRegisterStatsPullAtom[] = + u"android.permission.REGISTER_STATS_PULL_ATOM"; + + // Time limit for waiting for permissions. + static constexpr int kPermissionsWaitTimeoutSeconds = 30; +}; + +} // namespace gpuwork +} // namespace android diff --git a/services/gpuservice/vts/Android.bp b/services/gpuservice/vts/Android.bp new file mode 100644 index 0000000000..83a40e7bbf --- /dev/null +++ b/services/gpuservice/vts/Android.bp @@ -0,0 +1,30 @@ +// Copyright 2022 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + default_applicable_licenses: ["frameworks_native_license"], +} + +java_test_host { + name: "GpuServiceVendorTests", + srcs: ["src/**/*.java"], + libs: [ + "tradefed", + "vts-core-tradefed-harness", + ], + test_suites: [ + "general-tests", + "vts", + ], +} diff --git a/services/gpuservice/vts/AndroidTest.xml b/services/gpuservice/vts/AndroidTest.xml new file mode 100644 index 0000000000..02ca07f968 --- /dev/null +++ b/services/gpuservice/vts/AndroidTest.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2022 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<configuration description="Runs GpuServiceVendorTests"> + <test class="com.android.tradefed.testtype.HostTest" > + <option name="jar" value="GpuServiceVendorTests.jar" /> + </test> +</configuration> diff --git a/services/gpuservice/vts/OWNERS b/services/gpuservice/vts/OWNERS new file mode 100644 index 0000000000..e789052fa3 --- /dev/null +++ b/services/gpuservice/vts/OWNERS @@ -0,0 +1,7 @@ +# Bug component: 653544 +paulthomson@google.com +pbaiget@google.com +lfy@google.com +chrisforbes@google.com +lpy@google.com +alecmouri@google.com diff --git a/services/gpuservice/vts/TEST_MAPPING b/services/gpuservice/vts/TEST_MAPPING new file mode 100644 index 0000000000..b33e9624e2 --- /dev/null +++ b/services/gpuservice/vts/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "GpuServiceVendorTests" + } + ] +} diff --git a/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java b/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java new file mode 100644 index 0000000000..4a77d9ab92 --- /dev/null +++ b/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java @@ -0,0 +1,98 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.tests.gpuservice; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import com.android.tradefed.util.CommandResult; +import com.android.tradefed.util.CommandStatus; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.stream.Collectors; + + +@RunWith(DeviceJUnit4ClassRunner.class) +public class GpuWorkTracepointTest extends BaseHostJUnit4Test { + + private static final String CPU_FREQUENCY_TRACEPOINT_FORMAT_PATH = + "/sys/kernel/tracing/events/power/cpu_frequency/format"; + private static final String GPU_WORK_PERIOD_TRACEPOINT_FORMAT_PATH = + "/sys/kernel/tracing/events/power/gpu_work_period/format"; + + @Test + public void testReadTracingEvents() throws Exception { + // Test |testGpuWorkPeriodTracepointFormat| is dependent on whether certain tracepoint + // paths exist. This means the test will vacuously pass if the tracepoint file system is + // inaccessible. Thus, as a basic check, we make sure the CPU frequency tracepoint format + // is accessible. If not, something is probably fundamentally broken about the tracing + // file system. + CommandResult commandResult = getDevice().executeShellV2Command( + String.format("cat %s", CPU_FREQUENCY_TRACEPOINT_FORMAT_PATH)); + + assertEquals(String.format( + "Failed to read \"%s\". This probably means that the tracing file system " + + "is fundamentally broken in some way, possibly due to bad " + + "permissions.", + CPU_FREQUENCY_TRACEPOINT_FORMAT_PATH), + commandResult.getStatus(), CommandStatus.SUCCESS); + } + + @Test + public void testGpuWorkPeriodTracepointFormat() throws Exception { + CommandResult commandResult = getDevice().executeShellV2Command( + String.format("cat %s", GPU_WORK_PERIOD_TRACEPOINT_FORMAT_PATH)); + + // If we failed to cat the tracepoint format then the test ends here. + assumeTrue(String.format("Failed to cat the gpu_work_period tracepoint format at %s", + GPU_WORK_PERIOD_TRACEPOINT_FORMAT_PATH), + commandResult.getStatus().equals(CommandStatus.SUCCESS)); + + // Otherwise, we check that the fields match the expected fields. + String actualFields = Arrays.stream( + commandResult.getStdout().trim().split("\n")).filter( + s -> s.startsWith("\tfield:")).collect( + Collectors.joining("\n")); + + String expectedFields = String.join("\n", + "\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;", + "\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;", + "\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\tsigned:0;", + "\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;", + "\tfield:u32 uid;\toffset:8;\tsize:4;\tsigned:0;", + "\tfield:u32 frequency;\toffset:12;\tsize:4;\tsigned:0;", + "\tfield:u64 start_time;\toffset:16;\tsize:8;\tsigned:0;", + "\tfield:u64 end_time;\toffset:24;\tsize:8;\tsigned:0;", + "\tfield:u64 flags;\toffset:32;\tsize:8;\tsigned:0;", + "\tfield:u32 thermally_throttled_max_frequency_khz;\toffset:40;\tsize:4;\tsigned:0;" + ); + + // We use |fail| rather than |assertEquals| because it allows us to give a clearer message. + if (!expectedFields.equals(actualFields)) { + String message = String.format( + "Tracepoint format given by \"%s\" does not match the expected format.\n" + + "Expected fields:\n%s\n\nActual fields:\n%s\n\n", + GPU_WORK_PERIOD_TRACEPOINT_FORMAT_PATH, expectedFields, actualFields); + fail(message); + } + } +} diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index 19cad7b9ad..6c4b11e0e5 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -29,8 +29,6 @@ #endif #include <unordered_set> -#include <android/hardware/input/classifier/1.0/IInputClassifier.h> - #define INDENT1 " " #define INDENT2 " " #define INDENT3 " " diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h index a6baf2f56d..e00028364a 100644 --- a/services/inputflinger/InputManager.h +++ b/services/inputflinger/InputManager.h @@ -33,7 +33,6 @@ #include <utils/Errors.h> #include <utils/RefBase.h> #include <utils/Timers.h> -#include <utils/Vector.h> using android::os::BnInputFlinger; diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index 9bc7b8e30e..517d383b5a 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -1254,6 +1254,11 @@ void SensorService::makeUuidsIntoIdsForSensorList(Vector<Sensor> &sensorList) co for (auto &sensor : sensorList) { int32_t id = getIdFromUuid(sensor.getUuid()); sensor.setId(id); + // The sensor UUID must always be anonymized here for non privileged clients. + // There is no other checks after this point before returning to client process. + if (!isAudioServerOrSystemServerUid(IPCThreadState::self()->getCallingUid())) { + sensor.anonymizeUuid(); + } } } diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index 9b6d01ab71..b009829ed6 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -26,6 +26,7 @@ #include <binder/IUidObserver.h> #include <cutils/compiler.h> #include <cutils/multiuser.h> +#include <private/android_filesystem_config.h> #include <sensor/ISensorServer.h> #include <sensor/ISensorEventConnection.h> #include <sensor/Sensor.h> @@ -447,6 +448,10 @@ private: // Removes the capped rate on active direct connections (when the mic toggle is flipped to off) void uncapRates(userid_t userId); + static inline bool isAudioServerOrSystemServerUid(uid_t uid) { + return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER; + } + static uint8_t sHmacGlobalKey[128]; static bool sHmacGlobalKeyIsValid; diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index a4dd32d92f..3a1dc7cdd3 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -190,8 +190,6 @@ filegroup { "Scheduler/MessageQueue.cpp", "Scheduler/RefreshRateConfigs.cpp", "Scheduler/Scheduler.cpp", - "Scheduler/SchedulerUtils.cpp", - "Scheduler/Timer.cpp", "Scheduler/VSyncDispatchTimerQueue.cpp", "Scheduler/VSyncPredictor.cpp", "Scheduler/VSyncReactor.cpp", @@ -229,7 +227,6 @@ cc_defaults { "libcutils", "libdisplayservicehidl", "libhidlbase", - "liblayers_proto", "liblog", "libprocessgroup", "libsync", diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index d61a4cbd01..e797b5d4bb 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -164,7 +164,7 @@ std::optional<compositionengine::LayerFE::LayerSettings> BufferLayer::prepareCli const bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) || ((isSecure() || isProtected()) && !targetSettings.isSecure); const bool bufferCanBeUsedAsHwTexture = - mBufferInfo.mBuffer->getBuffer()->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE; + mBufferInfo.mBuffer->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE; compositionengine::LayerFE::LayerSettings& layer = *result; if (blackOutLayer || !bufferCanBeUsedAsHwTexture) { ALOGE_IF(!bufferCanBeUsedAsHwTexture, "%s is blacked out as buffer is not gpu readable", @@ -201,7 +201,7 @@ std::optional<compositionengine::LayerFE::LayerSettings> BufferLayer::prepareCli } layer.source.buffer.maxLuminanceNits = maxLuminance; layer.frameNumber = mCurrentFrameNumber; - layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer()->getId() : 0; + layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0; const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || bufferNeedsFiltering(); @@ -436,7 +436,7 @@ void BufferLayer::onPostComposition(const DisplayDevice* display, void BufferLayer::gatherBufferInfo() { mBufferInfo.mPixelFormat = - !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getBuffer()->format; + !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getPixelFormat(); mBufferInfo.mFrameLatencyNeeded = true; } @@ -533,10 +533,10 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, } if (oldBufferInfo.mBuffer != nullptr) { - uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight(); - if (bufWidth != uint32_t(oldBufferInfo.mBuffer->getBuffer()->width) || - bufHeight != uint32_t(oldBufferInfo.mBuffer->getBuffer()->height)) { + uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); + if (bufWidth != oldBufferInfo.mBuffer->getWidth() || + bufHeight != oldBufferInfo.mBuffer->getHeight()) { recomputeVisibleRegions = true; } } @@ -558,7 +558,7 @@ uint32_t BufferLayer::getEffectiveScalingMode() const { bool BufferLayer::isProtected() const { return (mBufferInfo.mBuffer != nullptr) && - (mBufferInfo.mBuffer->getBuffer()->getUsage() & GRALLOC_USAGE_PROTECTED); + (mBufferInfo.mBuffer->getUsage() & GRALLOC_USAGE_PROTECTED); } // As documented in libhardware header, formats in the range @@ -638,8 +638,8 @@ Rect BufferLayer::getBufferSize(const State& s) const { return Rect::INVALID_RECT; } - uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight(); + uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); // Undo any transformations on the buffer and return the result. if (mBufferInfo.mTransform & ui::Transform::ROT_90) { @@ -670,8 +670,8 @@ FloatRect BufferLayer::computeSourceBounds(const FloatRect& parentBounds) const return parentBounds; } - uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight(); + uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); // Undo any transformations on the buffer and return the result. if (mBufferInfo.mTransform & ui::Transform::ROT_90) { @@ -713,7 +713,7 @@ Rect BufferLayer::getBufferCrop() const { return mBufferInfo.mCrop; } else if (mBufferInfo.mBuffer != nullptr) { // otherwise we use the whole buffer - return mBufferInfo.mBuffer->getBuffer()->getBounds(); + return mBufferInfo.mBuffer->getBounds(); } else { // if we don't have a buffer yet, we use an empty/invalid crop return Rect(); @@ -820,6 +820,10 @@ bool BufferLayer::bufferNeedsFiltering() const { return isFixedSize(); } +const std::shared_ptr<renderengine::ExternalTexture>& BufferLayer::getExternalTexture() const { + return mBufferInfo.mBuffer; +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 34d11ac579..99267be673 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -111,6 +111,7 @@ public: ui::Dataspace getDataSpace() const override; sp<GraphicBuffer> getBuffer() const override; + const std::shared_ptr<renderengine::ExternalTexture>& getExternalTexture() const override; ui::Transform::RotationFlags getTransformHint() const override { return mTransformHint; } diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp index c79fa1104c..9ae45fc4cb 100644 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -41,6 +41,7 @@ #include <gui/SurfaceComposerClient.h> #include <private/gui/ComposerService.h> #include <renderengine/RenderEngine.h> +#include <renderengine/impl/ExternalTexture.h> #include <utils/Log.h> #include <utils/String8.h> #include <utils/Trace.h> @@ -208,8 +209,9 @@ status_t BufferLayerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t pres if (mImages[item->mSlot] == nullptr || mImages[item->mSlot]->getBuffer() == nullptr || mImages[item->mSlot]->getBuffer()->getId() != item->mGraphicBuffer->getId()) { mImages[item->mSlot] = std::make_shared< - renderengine::ExternalTexture>(item->mGraphicBuffer, mRE, - renderengine::ExternalTexture::Usage::READABLE); + renderengine::impl::ExternalTexture>(item->mGraphicBuffer, mRE, + renderengine::impl::ExternalTexture:: + Usage::READABLE); } } @@ -462,8 +464,9 @@ void BufferLayerConsumer::onBufferAvailable(const BufferItem& item) { if (oldImage == nullptr || oldImage->getBuffer() == nullptr || oldImage->getBuffer()->getId() != item.mGraphicBuffer->getId()) { mImages[item.mSlot] = std::make_shared< - renderengine::ExternalTexture>(item.mGraphicBuffer, mRE, - renderengine::ExternalTexture::Usage::READABLE); + renderengine::impl::ExternalTexture>(item.mGraphicBuffer, mRE, + renderengine::impl::ExternalTexture:: + Usage::READABLE); } } } diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 2fac880065..0c938723ba 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -295,8 +295,8 @@ bool BufferStateLayer::updateGeometry() { return assignTransform(&mDrawingState.transform, t); } - uint32_t bufferWidth = mDrawingState.buffer->getBuffer()->getWidth(); - uint32_t bufferHeight = mDrawingState.buffer->getBuffer()->getHeight(); + uint32_t bufferWidth = mDrawingState.buffer->getWidth(); + uint32_t bufferHeight = mDrawingState.buffer->getHeight(); // Undo any transformations on the buffer. if (mDrawingState.bufferTransform & ui::Transform::ROT_90) { std::swap(bufferWidth, bufferHeight); @@ -368,46 +368,13 @@ bool BufferStateLayer::addFrameEvent(const sp<Fence>& acquireFence, nsecs_t post return true; } -std::shared_ptr<renderengine::ExternalTexture> BufferStateLayer::getBufferFromBufferData( - const BufferData& bufferData) { - bool cacheIdChanged = bufferData.flags.test(BufferData::BufferDataChange::cachedBufferChanged); - bool bufferSizeExceedsLimit = false; - std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr; - if (cacheIdChanged && bufferData.buffer != nullptr) { - bufferSizeExceedsLimit = - mFlinger->exceedsMaxRenderTargetSize(bufferData.buffer->getWidth(), - bufferData.buffer->getHeight()); - if (!bufferSizeExceedsLimit) { - ClientCache::getInstance().add(bufferData.cachedBuffer, bufferData.buffer); - buffer = ClientCache::getInstance().get(bufferData.cachedBuffer); - } - } else if (cacheIdChanged) { - buffer = ClientCache::getInstance().get(bufferData.cachedBuffer); - } else if (bufferData.buffer != nullptr) { - bufferSizeExceedsLimit = - mFlinger->exceedsMaxRenderTargetSize(bufferData.buffer->getWidth(), - bufferData.buffer->getHeight()); - if (!bufferSizeExceedsLimit) { - buffer = std::make_shared< - renderengine::ExternalTexture>(bufferData.buffer, mFlinger->getRenderEngine(), - renderengine::ExternalTexture::Usage::READABLE); - } - } - ALOGE_IF(bufferSizeExceedsLimit, - "Attempted to create an ExternalTexture for layer %s that exceeds render target size " - "limit.", - getDebugName()); - return buffer; -} - -bool BufferStateLayer::setBuffer(const BufferData& bufferData, nsecs_t postTime, +bool BufferStateLayer::setBuffer(std::shared_ptr<renderengine::ExternalTexture>& buffer, + const BufferData& bufferData, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info) { ATRACE_CALL(); - const std::shared_ptr<renderengine::ExternalTexture>& buffer = - getBufferFromBufferData(bufferData); if (!buffer) { return false; } @@ -419,8 +386,9 @@ bool BufferStateLayer::setBuffer(const BufferData& bufferData, nsecs_t postTime, if (mDrawingState.buffer) { mReleasePreviousBuffer = true; - if (mDrawingState.buffer != mBufferInfo.mBuffer || - mDrawingState.frameNumber != mBufferInfo.mFrameNumber) { + if (!mBufferInfo.mBuffer || + (!mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer) || + mDrawingState.frameNumber != mBufferInfo.mFrameNumber)) { // If mDrawingState has a buffer, and we are about to update again // before swapping to drawing state, then the first buffer will be // dropped and we should decrement the pending buffer count and @@ -448,7 +416,7 @@ bool BufferStateLayer::setBuffer(const BufferData& bufferData, nsecs_t postTime, mDrawingState.frameNumber = frameNumber; mDrawingState.releaseBufferListener = bufferData.releaseBufferListener; - mDrawingState.buffer = buffer; + mDrawingState.buffer = std::move(buffer); mDrawingState.clientCacheId = bufferData.cachedBuffer; mDrawingState.acquireFence = bufferData.flags.test(BufferData::BufferDataChange::fenceChanged) @@ -484,8 +452,8 @@ bool BufferStateLayer::setBuffer(const BufferData& bufferData, nsecs_t postTime, setFrameTimelineVsyncForBufferTransaction(info, postTime); - if (buffer && dequeueTime && *dequeueTime != 0) { - const uint64_t bufferId = buffer->getBuffer()->getId(); + if (dequeueTime && *dequeueTime != 0) { + const uint64_t bufferId = mDrawingState.buffer->getId(); mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str()); mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, *dequeueTime, FrameTracer::FrameEvent::DEQUEUE); @@ -493,8 +461,8 @@ bool BufferStateLayer::setBuffer(const BufferData& bufferData, nsecs_t postTime, FrameTracer::FrameEvent::QUEUE); } - mDrawingState.width = mDrawingState.buffer->getBuffer()->getWidth(); - mDrawingState.height = mDrawingState.buffer->getBuffer()->getHeight(); + mDrawingState.width = mDrawingState.buffer->getWidth(); + mDrawingState.height = mDrawingState.buffer->getHeight(); mDrawingState.releaseBufferEndpoint = bufferData.releaseBufferEndpoint; return true; } @@ -599,8 +567,8 @@ Rect BufferStateLayer::getBufferSize(const State& /*s*/) const { return Rect::INVALID_RECT; } - uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight(); + uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); // Undo any transformations on the buffer and return the result. if (mBufferInfo.mTransform & ui::Transform::ROT_90) { @@ -709,7 +677,7 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse } const int32_t layerId = getSequence(); - const uint64_t bufferId = mDrawingState.buffer->getBuffer()->getId(); + const uint64_t bufferId = mDrawingState.buffer->getId(); const uint64_t frameNumber = mDrawingState.frameNumber; const auto acquireFence = std::make_shared<FenceTime>(mDrawingState.acquireFence); mFlinger->mTimeStats->setAcquireFence(layerId, frameNumber, acquireFence); @@ -749,7 +717,7 @@ status_t BufferStateLayer::updateActiveBuffer() { return BAD_VALUE; } - if (!mBufferInfo.mBuffer || s.buffer->getBuffer() != mBufferInfo.mBuffer->getBuffer()) { + if (!mBufferInfo.mBuffer || !s.buffer->hasSameBuffer(*mBufferInfo.mBuffer)) { decrementPendingBufferCount(); } @@ -874,10 +842,10 @@ uint32_t BufferStateLayer::getEffectiveScalingMode() const { Rect BufferStateLayer::computeBufferCrop(const State& s) { if (s.buffer && !s.bufferCrop.isEmpty()) { Rect bufferCrop; - s.buffer->getBuffer()->getBounds().intersect(s.bufferCrop, &bufferCrop); + s.buffer->getBounds().intersect(s.bufferCrop, &bufferCrop); return bufferCrop; } else if (s.buffer) { - return s.buffer->getBuffer()->getBounds(); + return s.buffer->getBounds(); } else { return s.bufferCrop; } @@ -898,8 +866,8 @@ bool BufferStateLayer::bufferNeedsFiltering() const { return false; } - int32_t bufferWidth = s.buffer->getBuffer()->width; - int32_t bufferHeight = s.buffer->getBuffer()->height; + int32_t bufferWidth = static_cast<int32_t>(s.buffer->getWidth()); + int32_t bufferHeight = static_cast<int32_t>(s.buffer->getHeight()); // Undo any transformations on the buffer and return the result. if (s.bufferTransform & ui::Transform::ROT_90) { diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index eea700cf7b..2f613d7f26 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -57,7 +57,8 @@ public: bool setTransform(uint32_t transform) override; bool setTransformToDisplayInverse(bool transformToDisplayInverse) override; bool setCrop(const Rect& crop) override; - bool setBuffer(const BufferData& bufferData, nsecs_t postTime, nsecs_t desiredPresentTime, + bool setBuffer(std::shared_ptr<renderengine::ExternalTexture>& /* buffer */, + const BufferData& bufferData, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info) override; bool setDataspace(ui::Dataspace dataspace) override; @@ -136,9 +137,6 @@ private: bool bufferNeedsFiltering() const override; - std::shared_ptr<renderengine::ExternalTexture> getBufferFromBufferData( - const BufferData& bufferData); - ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID; uint64_t mPreviousReleasedFrameNumber = 0; diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp index e7b8995703..3c7b9d93aa 100644 --- a/services/surfaceflinger/ClientCache.cpp +++ b/services/surfaceflinger/ClientCache.cpp @@ -22,6 +22,7 @@ #include <cinttypes> #include <android-base/stringprintf.h> +#include <renderengine/impl/ExternalTexture.h> #include "ClientCache.h" @@ -109,8 +110,9 @@ bool ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& bu "Attempted to build the ClientCache before a RenderEngine instance was " "ready!"); processBuffers[id].buffer = std::make_shared< - renderengine::ExternalTexture>(buffer, *mRenderEngine, - renderengine::ExternalTexture::Usage::READABLE); + renderengine::impl::ExternalTexture>(buffer, *mRenderEngine, + renderengine::impl::ExternalTexture::Usage:: + READABLE); return true; } diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index a19d23febf..12c2c8eb38 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -28,6 +28,7 @@ #include <log/log.h> #include <renderengine/ExternalTexture.h> #include <renderengine/RenderEngine.h> +#include <renderengine/impl/ExternalTexture.h> #include <system/window.h> #include <ui/GraphicBuffer.h> #include <ui/Rect.h> @@ -182,9 +183,10 @@ std::shared_ptr<renderengine::ExternalTexture> RenderSurface::dequeueBuffer( mTexture = texture; } else { mTexture = std::make_shared< - renderengine::ExternalTexture>(GraphicBuffer::from(buffer), - mCompositionEngine.getRenderEngine(), - renderengine::ExternalTexture::Usage::WRITEABLE); + renderengine::impl::ExternalTexture>(GraphicBuffer::from(buffer), + mCompositionEngine.getRenderEngine(), + renderengine::impl::ExternalTexture::Usage:: + WRITEABLE); } mTextureCache.push_back(mTexture); if (mTextureCache.size() > mMaxTextureCacheSize) { diff --git a/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp b/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp index 497c433c76..54ecb5691d 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp @@ -20,6 +20,7 @@ #define LOG_TAG "Planner" #include <compositionengine/impl/planner/TexturePool.h> +#include <renderengine/impl/ExternalTexture.h> #include <utils/Log.h> namespace android::compositionengine::impl::planner { @@ -82,16 +83,19 @@ void TexturePool::returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& std::shared_ptr<renderengine::ExternalTexture> TexturePool::genTexture() { LOG_ALWAYS_FATAL_IF(!mSize.isValid(), "Attempted to generate texture with invalid size"); return std::make_shared< - renderengine::ExternalTexture>(sp<GraphicBuffer>:: - make(mSize.getWidth(), mSize.getHeight(), - HAL_PIXEL_FORMAT_RGBA_8888, 1, - GraphicBuffer::USAGE_HW_RENDER | - GraphicBuffer::USAGE_HW_COMPOSER | - GraphicBuffer::USAGE_HW_TEXTURE, - "Planner"), - mRenderEngine, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage::WRITEABLE); + renderengine::impl:: + ExternalTexture>(sp<GraphicBuffer>:: + make(static_cast<uint32_t>(mSize.getWidth()), + static_cast<uint32_t>(mSize.getHeight()), + HAL_PIXEL_FORMAT_RGBA_8888, 1U, + static_cast<uint64_t>( + GraphicBuffer::USAGE_HW_RENDER | + GraphicBuffer::USAGE_HW_COMPOSER | + GraphicBuffer::USAGE_HW_TEXTURE), + "Planner"), + mRenderEngine, + renderengine::impl::ExternalTexture::Usage::READABLE | + renderengine::impl::ExternalTexture::Usage::WRITEABLE); } void TexturePool::setEnabled(bool enabled) { diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index f34b621adb..132ac022ab 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -24,6 +24,7 @@ #include <gtest/gtest.h> #include <log/log.h> +#include <renderengine/impl/ExternalTexture.h> #include <renderengine/mock/RenderEngine.h> #include <ui/PixelFormat.h> #include "MockHWC2.h" @@ -815,10 +816,11 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { auto& overrideInfo = mOutputLayer.editState().overrideInfo; overrideInfo.buffer = std::make_shared< - renderengine::ExternalTexture>(kOverrideBuffer, mRenderEngine, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage:: - WRITEABLE); + renderengine::impl::ExternalTexture>(kOverrideBuffer, mRenderEngine, + renderengine::impl::ExternalTexture::Usage:: + READABLE | + renderengine::impl::ExternalTexture:: + Usage::WRITEABLE); overrideInfo.acquireFence = kOverrideFence; overrideInfo.displayFrame = kOverrideDisplayFrame; overrideInfo.dataspace = kOverrideDataspace; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index f7c75337ff..b13e13cb20 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -26,6 +26,8 @@ #include <compositionengine/mock/RenderSurface.h> #include <ftl/future.h> #include <gtest/gtest.h> +#include <renderengine/ExternalTexture.h> +#include <renderengine/impl/ExternalTexture.h> #include <renderengine/mock/RenderEngine.h> #include <ui/Rect.h> #include <ui/Region.h> @@ -37,7 +39,6 @@ #include "MockHWC2.h" #include "RegionMatcher.h" #include "TestUtils.h" -#include "renderengine/ExternalTexture.h" namespace android::compositionengine { namespace { @@ -273,9 +274,10 @@ TEST_F(OutputTest, setLayerCachingEnabled_disablesCachingAndResetsOverrideInfo) // Inject some layers InjectedLayer layer; layer.outputLayerState.overrideInfo.buffer = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(), renderEngine, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage::WRITEABLE); + renderengine::impl:: + ExternalTexture>(new GraphicBuffer(), renderEngine, + renderengine::impl::ExternalTexture::Usage::READABLE | + renderengine::impl::ExternalTexture::Usage::WRITEABLE); injectOutputLayer(layer); // inject a null layer to check for null exceptions injectNullOutputLayer(); @@ -967,9 +969,10 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, peekThroughLayerChangesOrder) { mOutput->planComposition(); std::shared_ptr<renderengine::ExternalTexture> buffer = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(), renderEngine, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage::WRITEABLE); + renderengine::impl:: + ExternalTexture>(new GraphicBuffer(), renderEngine, + renderengine::impl::ExternalTexture::Usage::READABLE | + renderengine::impl::ExternalTexture::Usage::WRITEABLE); layer1.outputLayerState.overrideInfo.buffer = buffer; layer2.outputLayerState.overrideInfo.buffer = buffer; layer1.outputLayerState.overrideInfo.peekThroughLayer = layer3.outputLayer; @@ -3088,9 +3091,10 @@ struct OutputComposeSurfacesTest : public testing::Test { mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>(); StrictMock<OutputPartialMock> mOutput; std::shared_ptr<renderengine::ExternalTexture> mOutputBuffer = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage::WRITEABLE); + renderengine::impl:: + ExternalTexture>(new GraphicBuffer(), mRenderEngine, + renderengine::impl::ExternalTexture::Usage::READABLE | + renderengine::impl::ExternalTexture::Usage::WRITEABLE); std::optional<base::unique_fd> mReadyFence; }; @@ -3324,9 +3328,10 @@ TEST_F(OutputComposeSurfacesTest, clientCompositionIfBufferChanges) { .WillRepeatedly(Return()); const auto otherOutputBuffer = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage::WRITEABLE); + renderengine::impl:: + ExternalTexture>(new GraphicBuffer(), mRenderEngine, + renderengine::impl::ExternalTexture::Usage::READABLE | + renderengine::impl::ExternalTexture::Usage::WRITEABLE); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)) .WillOnce(Return(mOutputBuffer)) .WillOnce(Return(otherOutputBuffer)); diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index 7c8e41b53e..e5f9ebfbeb 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -27,6 +27,7 @@ #include <compositionengine/mock/OutputLayer.h> #include <gtest/gtest.h> #include <renderengine/ExternalTexture.h> +#include <renderengine/impl/ExternalTexture.h> #include <renderengine/mock/RenderEngine.h> #include <ui/GraphicBuffer.h> @@ -251,9 +252,10 @@ TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) { TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) { const auto buffer = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage::WRITEABLE); + renderengine::impl:: + ExternalTexture>(new GraphicBuffer(), mRenderEngine, + renderengine::impl::ExternalTexture::Usage::READABLE | + renderengine::impl::ExternalTexture::Usage::WRITEABLE); mSurface.mutableTextureForTest() = buffer; impl::OutputCompositionState state; @@ -269,8 +271,8 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) { } TEST_F(RenderSurfaceTest, queueBufferHandlesClientComposition) { - const auto buffer = std::make_shared<renderengine::ExternalTexture>(new GraphicBuffer(), - mRenderEngine, false); + const auto buffer = std::make_shared<renderengine::impl::ExternalTexture>(new GraphicBuffer(), + mRenderEngine, false); mSurface.mutableTextureForTest() = buffer; impl::OutputCompositionState state; @@ -288,8 +290,8 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesClientComposition) { } TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequest) { - const auto buffer = std::make_shared<renderengine::ExternalTexture>(new GraphicBuffer(), - mRenderEngine, false); + const auto buffer = std::make_shared<renderengine::impl::ExternalTexture>(new GraphicBuffer(), + mRenderEngine, false); mSurface.mutableTextureForTest() = buffer; impl::OutputCompositionState state; @@ -327,8 +329,8 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferY } TEST_F(RenderSurfaceTest, queueBufferHandlesNativeWindowQueueBufferFailureOnVirtualDisplay) { - const auto buffer = std::make_shared<renderengine::ExternalTexture>(new GraphicBuffer(), - mRenderEngine, false); + const auto buffer = std::make_shared<renderengine::impl::ExternalTexture>(new GraphicBuffer(), + mRenderEngine, false); mSurface.mutableTextureForTest() = buffer; impl::OutputCompositionState state; diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp index d5a117a597..4ae921d661 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp @@ -22,6 +22,7 @@ #include <gmock/gmock-actions.h> #include <gtest/gtest.h> #include <renderengine/ExternalTexture.h> +#include <renderengine/mock/FakeExternalTexture.h> #include <renderengine/mock/RenderEngine.h> #include <ui/GraphicTypes.h> #include <utils/Errors.h> @@ -702,9 +703,11 @@ TEST_F(CachedSetTest, addHolePunch) { std::vector<compositionengine::LayerFE::LayerSettings> clientCompList3; clientCompList3.push_back({}); - clientCompList3[0].source.buffer.buffer = std::make_shared< - renderengine::ExternalTexture>(sp<GraphicBuffer>::make(), mRenderEngine, - renderengine::ExternalTexture::READABLE); + clientCompList3[0].source.buffer.buffer = + std::make_shared<renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, + 1ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0ULL /*usage*/); EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1)); EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2)); @@ -901,9 +904,11 @@ TEST_F(CachedSetTest, addBlur) { std::vector<compositionengine::LayerFE::LayerSettings> clientCompList3; clientCompList3.push_back({}); - clientCompList3[0].source.buffer.buffer = std::make_shared< - renderengine::ExternalTexture>(sp<GraphicBuffer>::make(), mRenderEngine, - renderengine::ExternalTexture::READABLE); + clientCompList3[0].source.buffer.buffer = + std::make_shared<renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, + 1ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0ULL /*usage*/); EXPECT_CALL(*layerFE1, prepareClientCompositionList(ClientCompositionTargetSettingsBlurSettingsEq( diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp index 35d051ebea..58dc244402 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp @@ -23,6 +23,7 @@ #include <gtest/gtest.h> #include <renderengine/ExternalTexture.h> #include <renderengine/LayerSettings.h> +#include <renderengine/impl/ExternalTexture.h> #include <renderengine/mock/RenderEngine.h> #include <chrono> @@ -639,9 +640,10 @@ TEST_F(FlattenerTest, flattenLayers_pip) { LayerFE::LayerSettings{}, }; clientCompositionList[0].source.buffer.buffer = std::make_shared< - renderengine::ExternalTexture>(mTestLayers[2]->layerFECompositionState.buffer, - mRenderEngine, - renderengine::ExternalTexture::Usage::READABLE); + renderengine::impl::ExternalTexture>(mTestLayers[2]->layerFECompositionState.buffer, + mRenderEngine, + renderengine::impl::ExternalTexture::Usage:: + READABLE); EXPECT_CALL(*mTestLayers[2]->layerFE, prepareClientCompositionList(_)) .WillOnce(Return(clientCompositionList)); @@ -711,9 +713,10 @@ TEST_F(FlattenerTest, flattenLayers_holePunchSingleLayer) { LayerFE::LayerSettings{}, }; clientCompositionList[0].source.buffer.buffer = std::make_shared< - renderengine::ExternalTexture>(mTestLayers[1]->layerFECompositionState.buffer, - mRenderEngine, - renderengine::ExternalTexture::Usage::READABLE); + renderengine::impl::ExternalTexture>(mTestLayers[1]->layerFECompositionState.buffer, + mRenderEngine, + renderengine::impl::ExternalTexture::Usage:: + READABLE); EXPECT_CALL(*mTestLayers[1]->layerFE, prepareClientCompositionList(_)) .WillOnce(Return(clientCompositionList)); @@ -781,9 +784,10 @@ TEST_F(FlattenerTest, flattenLayers_holePunchSingleColorLayer) { LayerFE::LayerSettings{}, }; clientCompositionList[0].source.buffer.buffer = std::make_shared< - renderengine::ExternalTexture>(mTestLayers[1]->layerFECompositionState.buffer, - mRenderEngine, - renderengine::ExternalTexture::Usage::READABLE); + renderengine::impl::ExternalTexture>(mTestLayers[1]->layerFECompositionState.buffer, + mRenderEngine, + renderengine::impl::ExternalTexture::Usage:: + READABLE); EXPECT_CALL(*mTestLayers[1]->layerFE, prepareClientCompositionList(_)) .WillOnce(Return(clientCompositionList)); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5948a78559..fa2c92dd32 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -101,7 +101,9 @@ Layer::Layer(const LayerCreationArgs& args) if (args.flags & ISurfaceComposerClient::eSecure) layerFlags |= layer_state_t::eLayerSecure; if (args.flags & ISurfaceComposerClient::eSkipScreenshot) layerFlags |= layer_state_t::eLayerSkipScreenshot; - + if (args.sequence) { + sSequence = *args.sequence + 1; + } mDrawingState.flags = layerFlags; mDrawingState.active_legacy.transform.set(0, 0); mDrawingState.crop.makeInvalid(); @@ -2022,9 +2024,9 @@ LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags, void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, const DisplayDevice* display) { const ui::Transform transform = getTransform(); - auto buffer = getBuffer(); + auto buffer = getExternalTexture(); if (buffer != nullptr) { - LayerProtoHelper::writeToProto(buffer, + LayerProtoHelper::writeToProto(*buffer, [&]() { return layerInfo->mutable_active_buffer(); }); LayerProtoHelper::writeToProtoDeprecated(ui::Transform(getBufferTransform()), layerInfo->mutable_buffer_transform()); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 31cdf0b3e4..4cdd8fa24b 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -416,8 +416,10 @@ public: // Used only to set BufferStateLayer state virtual bool setTransform(uint32_t /*transform*/) { return false; }; virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; }; - virtual bool setBuffer(const BufferData&, nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/, - bool /*isAutoTimestamp*/, std::optional<nsecs_t> /* dequeueTime */, + virtual bool setBuffer(std::shared_ptr<renderengine::ExternalTexture>& /* buffer */, + const BufferData& /* bufferData */, nsecs_t /* postTime */, + nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/, + std::optional<nsecs_t> /* dequeueTime */, const FrameTimelineInfo& /*info*/) { return false; }; @@ -563,6 +565,9 @@ public: virtual uint32_t getBufferTransform() const { return 0; } virtual sp<GraphicBuffer> getBuffer() const { return nullptr; } + virtual const std::shared_ptr<renderengine::ExternalTexture>& getExternalTexture() const { + return mDrawingState.buffer; + }; virtual ui::Transform::RotationFlags getTransformHint() const { return ui::Transform::ROT_0; } diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp index ee23561136..015caa6a9b 100644 --- a/services/surfaceflinger/LayerProtoHelper.cpp +++ b/services/surfaceflinger/LayerProtoHelper.cpp @@ -154,16 +154,16 @@ void LayerProtoHelper::writeTransformToProto(const ui::Transform& transform, } } -void LayerProtoHelper::writeToProto(const sp<GraphicBuffer>& buffer, +void LayerProtoHelper::writeToProto(const renderengine::ExternalTexture& buffer, std::function<ActiveBufferProto*()> getActiveBufferProto) { - if (buffer->getWidth() != 0 || buffer->getHeight() != 0 || buffer->getStride() != 0 || - buffer->format != 0) { + if (buffer.getBuffer()->getWidth() != 0 || buffer.getBuffer()->getHeight() != 0 || + buffer.getBuffer()->getUsage() != 0 || buffer.getBuffer()->getPixelFormat() != 0) { // Use a lambda do avoid writing the object header when the object is empty ActiveBufferProto* activeBufferProto = getActiveBufferProto(); - activeBufferProto->set_width(buffer->getWidth()); - activeBufferProto->set_height(buffer->getHeight()); - activeBufferProto->set_stride(buffer->getStride()); - activeBufferProto->set_format(buffer->format); + activeBufferProto->set_width(buffer.getBuffer()->getWidth()); + activeBufferProto->set_height(buffer.getBuffer()->getHeight()); + activeBufferProto->set_format(buffer.getBuffer()->getPixelFormat()); + activeBufferProto->set_usage(buffer.getBuffer()->getUsage()); } } diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h index 249ec4281f..6ade1435e5 100644 --- a/services/surfaceflinger/LayerProtoHelper.h +++ b/services/surfaceflinger/LayerProtoHelper.h @@ -15,6 +15,7 @@ */ #include <layerproto/LayerProtoHeader.h> +#include <renderengine/ExternalTexture.h> #include <Layer.h> #include <gui/WindowInfo.h> @@ -48,7 +49,7 @@ public: TransformProto* transformProto); static void writeTransformToProto(const ui::Transform& transform, TransformProto* transformProto); - static void writeToProto(const sp<GraphicBuffer>& buffer, + static void writeToProto(const renderengine::ExternalTexture& buffer, std::function<ActiveBufferProto*()> getActiveBufferProto); static void writeToProto(const gui::WindowInfo& inputInfo, const wp<Layer>& touchableRegionBounds, diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index da8c3e062c..ff30348151 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -31,6 +31,7 @@ #include <cutils/properties.h> #include <ftl/future.h> #include <gui/SyncScreenCaptureListener.h> +#include <renderengine/impl/ExternalTexture.h> #include <ui/DisplayStatInfo.h> #include <utils/Trace.h> @@ -351,8 +352,9 @@ void RegionSamplingThread::captureSample() { LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureSample: Buffer failed to allocate: %d", bufferStatus); buffer = std::make_shared< - renderengine::ExternalTexture>(graphicBuffer, mFlinger.getRenderEngine(), - renderengine::ExternalTexture::Usage::WRITEABLE); + renderengine::impl::ExternalTexture>(graphicBuffer, mFlinger.getRenderEngine(), + renderengine::impl::ExternalTexture::Usage:: + WRITEABLE); } auto captureScreenResultFuture = diff --git a/services/surfaceflinger/Scheduler/Android.bp b/services/surfaceflinger/Scheduler/Android.bp index 409d09858f..5de796d742 100644 --- a/services/surfaceflinger/Scheduler/Android.bp +++ b/services/surfaceflinger/Scheduler/Android.bp @@ -16,6 +16,8 @@ cc_defaults { ], shared_libs: [ "libbase", + "libcutils", + "liblog", "libutils", ], } @@ -26,10 +28,36 @@ cc_library_headers { export_include_dirs: ["include"], } +// TODO(b/185535769): Remove libsurfaceflinger_unittest's dependency on AsyncCallRecorder. +cc_library_headers { + name: "libscheduler_test_headers", + defaults: ["libscheduler_defaults"], + export_include_dirs: ["tests"], +} + cc_library_static { name: "libscheduler", defaults: ["libscheduler_defaults"], - srcs: [], + srcs: [ + "src/Timer.cpp", + ], local_include_dirs: ["include"], export_include_dirs: ["include"], } + +cc_test { + name: "libscheduler_test", + test_suites: ["device-tests"], + defaults: ["libscheduler_defaults"], + srcs: [ + "tests/TimerTest.cpp", + ], + static_libs: [ + "libgmock", + "libgtest", + "libscheduler", + ], + sanitize: { + address: true, + }, +} diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 74a2ca786c..0efc28b71d 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -33,7 +33,6 @@ #include "../Layer.h" #include "LayerInfo.h" -#include "SchedulerUtils.h" namespace android::scheduler { diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index 2d88a4fb9d..8a3b0b97e4 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -29,7 +29,6 @@ #include "LayerHistory.h" #include "RefreshRateConfigs.h" -#include "SchedulerUtils.h" namespace android { diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index eaec789257..89d861fdfd 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -617,7 +617,7 @@ const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const auto [refreshRate, score] = *i; ALOGV("%s scores %.2f", refreshRate->getName().c_str(), score); - ATRACE_INT(refreshRate->getName().c_str(), round<int>(score * 100)); + ATRACE_INT(refreshRate->getName().c_str(), static_cast<int>(std::round(score * 100))); if (score > max * (1 + kEpsilon)) { max = score; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index ff36eee075..849d297f2c 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -30,7 +30,6 @@ #include "DisplayHardware/DisplayMode.h" #include "DisplayHardware/HWComposer.h" #include "Scheduler/OneShotTimer.h" -#include "Scheduler/SchedulerUtils.h" #include "Scheduler/StrongTyping.h" namespace android::scheduler { diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h index 23ebb061e4..f1ad75597a 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateStats.h +++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h @@ -25,7 +25,6 @@ #include <scheduler/Fps.h> -#include "Scheduler/SchedulerUtils.h" #include "TimeStats/TimeStats.h" namespace android::scheduler { diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 48d54318e1..a85e7487e0 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -45,7 +45,6 @@ #include "FrameRateOverrideMappings.h" #include "InjectVSyncSource.h" #include "OneShotTimer.h" -#include "SchedulerUtils.h" #include "SurfaceFlingerProperties.h" #include "VSyncPredictor.h" #include "VSyncReactor.h" diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 579fabb400..bc9024a9f1 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -17,6 +17,7 @@ #pragma once #include <atomic> +#include <cstdint> #include <functional> #include <future> #include <memory> @@ -39,9 +40,37 @@ #include "MessageQueue.h" #include "OneShotTimer.h" #include "RefreshRateConfigs.h" -#include "SchedulerUtils.h" #include "VsyncSchedule.h" +namespace android::scheduler { + +// Opaque handle to scheduler connection. +struct ConnectionHandle { + using Id = std::uintptr_t; + static constexpr Id INVALID_ID = static_cast<Id>(-1); + + Id id = INVALID_ID; + + explicit operator bool() const { return id != INVALID_ID; } +}; + +inline bool operator==(ConnectionHandle lhs, ConnectionHandle rhs) { + return lhs.id == rhs.id; +} + +} // namespace android::scheduler + +namespace std { + +template <> +struct hash<android::scheduler::ConnectionHandle> { + size_t operator()(android::scheduler::ConnectionHandle handle) const { + return hash<android::scheduler::ConnectionHandle::Id>()(handle.id); + } +}; + +} // namespace std + namespace android { class FenceTime; diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.cpp b/services/surfaceflinger/Scheduler/SchedulerUtils.cpp deleted file mode 100644 index e8e0444e6f..0000000000 --- a/services/surfaceflinger/Scheduler/SchedulerUtils.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "SchedulerUtils.h" - -#include <cinttypes> -#include <numeric> -#include <unordered_map> -#include <vector> - -namespace android { -namespace scheduler { - -int64_t calculate_median(std::vector<int64_t>* v) { - if (!v || v->empty()) { - return 0; - } - - size_t n = v->size() / 2; - nth_element(v->begin(), v->begin() + static_cast<long>(n), v->end()); - return v->at(n); -} - -} // namespace scheduler -} // namespace android - diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h deleted file mode 100644 index 04a4cd1152..0000000000 --- a/services/surfaceflinger/Scheduler/SchedulerUtils.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <utils/Timers.h> -#include <cinttypes> -#include <numeric> -#include <unordered_map> -#include <vector> - -namespace android::scheduler { - -// Opaque handle to scheduler connection. -struct ConnectionHandle { - using Id = std::uintptr_t; - static constexpr Id INVALID_ID = static_cast<Id>(-1); - - Id id = INVALID_ID; - - explicit operator bool() const { return id != INVALID_ID; } -}; - -inline bool operator==(ConnectionHandle lhs, ConnectionHandle rhs) { - return lhs.id == rhs.id; -} - -// Calculates the statistical mean (average) in the data structure (array, vector). The -// function does not modify the contents of the array. -template <typename T> -auto calculate_mean(const T& v) { - using V = typename T::value_type; - V sum = std::accumulate(v.begin(), v.end(), static_cast<V>(0)); - return sum / static_cast<V>(v.size()); -} - -// Calculates the statistical median in the vector. Return 0 if the vector is empty. The -// function modifies the vector contents. -int64_t calculate_median(std::vector<int64_t>* v); - -// Calculates the statistical mode in the vector. Return 0 if the vector is empty. -template <typename T> -auto calculate_mode(const T& v) { - if (v.empty()) { - return 0; - } - - // Create a map with all the counts for the indivicual values in the vector. - std::unordered_map<int64_t, int> counts; - for (int64_t value : v) { - counts[value]++; - } - - // Sort the map, and return the number with the highest count. If two numbers have - // the same count, first one is returned. - using ValueType = const decltype(counts)::value_type&; - const auto compareCounts = [](ValueType l, ValueType r) { return l.second <= r.second; }; - return static_cast<int>(std::max_element(counts.begin(), counts.end(), compareCounts)->first); -} - -template <class T, size_t N> -constexpr size_t arrayLen(T (&)[N]) { - return N; -} - -static constexpr size_t max64print = std::numeric_limits<nsecs_t>::digits10 + 1; - -template <typename T> -static inline T round(float f) { - return static_cast<T>(std::round(f)); -} - -} // namespace android::scheduler - -namespace std { - -template <> -struct hash<android::scheduler::ConnectionHandle> { - size_t operator()(android::scheduler::ConnectionHandle handle) const { - return hash<android::scheduler::ConnectionHandle::Id>()(handle.id); - } -}; - -} // namespace std diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h index b52706f727..2bfe204a33 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatch.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h @@ -16,17 +16,15 @@ #pragma once -#include <utils/Log.h> -#include <utils/Timers.h> #include <functional> #include <optional> #include <string> +#include <utils/Timers.h> + #include "StrongTyping.h" namespace android::scheduler { -class TimeKeeper; -class VSyncTracker; using ScheduleResult = std::optional<nsecs_t>; @@ -64,8 +62,7 @@ public: * invocation of callbackFn. * */ - virtual CallbackToken registerCallback(Callback const& callbackFn, - std::string callbackName) = 0; + virtual CallbackToken registerCallback(Callback, std::string callbackName) = 0; /* * Unregisters a callback. @@ -142,8 +139,9 @@ public: protected: VSyncDispatch() = default; - VSyncDispatch(VSyncDispatch const&) = delete; - VSyncDispatch& operator=(VSyncDispatch const&) = delete; + + VSyncDispatch(const VSyncDispatch&) = delete; + VSyncDispatch& operator=(const VSyncDispatch&) = delete; }; /* @@ -152,11 +150,11 @@ protected: */ class VSyncCallbackRegistration { public: - VSyncCallbackRegistration(VSyncDispatch&, VSyncDispatch::Callback const& callbackFn, - std::string const& callbackName); + VSyncCallbackRegistration(VSyncDispatch&, VSyncDispatch::Callback, std::string callbackName); + ~VSyncCallbackRegistration(); + VSyncCallbackRegistration(VSyncCallbackRegistration&&); VSyncCallbackRegistration& operator=(VSyncCallbackRegistration&&); - ~VSyncCallbackRegistration(); // See documentation for VSyncDispatch::schedule. ScheduleResult schedule(VSyncDispatch::ScheduleTiming scheduleTiming); @@ -165,9 +163,6 @@ public: CancelResult cancel(); private: - VSyncCallbackRegistration(VSyncCallbackRegistration const&) = delete; - VSyncCallbackRegistration& operator=(VSyncCallbackRegistration const&) = delete; - std::reference_wrapper<VSyncDispatch> mDispatch; VSyncDispatch::CallbackToken mToken; bool mValidToken; diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp index b805bf68e4..27f43115c1 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp @@ -15,18 +15,24 @@ */ #define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include <vector> + #include <android-base/stringprintf.h> +#include <ftl/concat.h> #include <utils/Trace.h> -#include <vector> -#include "TimeKeeper.h" +#include <scheduler/TimeKeeper.h> + #include "VSyncDispatchTimerQueue.h" #include "VSyncTracker.h" namespace android::scheduler { + using base::StringAppendF; namespace { + nsecs_t getExpectedCallbackTime(nsecs_t nextVsyncTime, const VSyncDispatch::ScheduleTiming& timing) { return nextVsyncTime - timing.readyDuration - timing.workDuration; @@ -38,17 +44,17 @@ nsecs_t getExpectedCallbackTime(VSyncTracker& tracker, nsecs_t now, std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration)); return getExpectedCallbackTime(nextVsyncTime, timing); } + } // namespace VSyncDispatch::~VSyncDispatch() = default; VSyncTracker::~VSyncTracker() = default; -TimeKeeper::~TimeKeeper() = default; -VSyncDispatchTimerQueueEntry::VSyncDispatchTimerQueueEntry(std::string const& name, - VSyncDispatch::Callback const& cb, +VSyncDispatchTimerQueueEntry::VSyncDispatchTimerQueueEntry(std::string name, + VSyncDispatch::Callback callback, nsecs_t minVsyncDistance) - : mName(name), - mCallback(cb), + : mName(std::move(name)), + mCallback(std::move(callback)), mMinVsyncDistance(minVsyncDistance) {} std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::lastExecutedVsyncTarget() const { @@ -222,16 +228,6 @@ void VSyncDispatchTimerQueue::rearmTimer(nsecs_t now) { rearmTimerSkippingUpdateFor(now, mCallbacks.end()); } -void VSyncDispatchTimerQueue::TraceBuffer::note(std::string_view name, nsecs_t alarmIn, - nsecs_t vsFor) { - if (ATRACE_ENABLED()) { - snprintf(str_buffer.data(), str_buffer.size(), "%.4s%s%" PRId64 "%s%" PRId64, - name.substr(0, kMaxNamePrint).data(), kTraceNamePrefix, alarmIn, - kTraceNameSeparator, vsFor); - } - ATRACE_NAME(str_buffer.data()); -} - void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor( nsecs_t now, CallbackMap::iterator const& skipUpdateIt) { std::optional<nsecs_t> min; @@ -247,16 +243,18 @@ void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor( callback->update(mTracker, now); } auto const wakeupTime = *callback->wakeupTime(); - if (!min || (min && *min > wakeupTime)) { + if (!min || *min > wakeupTime) { nextWakeupName = callback->name(); min = wakeupTime; targetVsync = callback->targetVsync(); } } - if (min && (min < mIntendedWakeupTime)) { - if (targetVsync && nextWakeupName) { - mTraceBuffer.note(*nextWakeupName, *min - now, *targetVsync - now); + if (min && min < mIntendedWakeupTime) { + if (ATRACE_ENABLED() && nextWakeupName && targetVsync) { + ftl::Concat trace(ftl::truncated<5>(*nextWakeupName), " alarm in ", ns2us(*min - now), + "us; VSYNC in ", ns2us(*targetVsync - now), "us"); + ATRACE_NAME(trace.c_str()); } setTimer(*min, now); } else { @@ -305,13 +303,13 @@ void VSyncDispatchTimerQueue::timerCallback() { } VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback( - Callback const& callbackFn, std::string callbackName) { + Callback callback, std::string callbackName) { std::lock_guard lock(mMutex); return CallbackToken{ mCallbacks .emplace(++mCallbackToken, - std::make_shared<VSyncDispatchTimerQueueEntry>(callbackName, - callbackFn, + std::make_shared<VSyncDispatchTimerQueueEntry>(std::move(callbackName), + std::move(callback), mMinVsyncDistance)) .first->first}; } @@ -406,10 +404,10 @@ void VSyncDispatchTimerQueue::dump(std::string& result) const { } VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch, - VSyncDispatch::Callback const& callbackFn, - std::string const& callbackName) + VSyncDispatch::Callback callback, + std::string callbackName) : mDispatch(dispatch), - mToken(dispatch.registerCallback(callbackFn, callbackName)), + mToken(dispatch.registerCallback(std::move(callback), std::move(callbackName))), mValidToken(true) {} VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncCallbackRegistration&& other) diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h index 26237b63a3..3186d6d399 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h @@ -16,8 +16,6 @@ #pragma once -#include <android-base/thread_annotations.h> -#include <array> #include <functional> #include <memory> #include <mutex> @@ -25,11 +23,14 @@ #include <string_view> #include <unordered_map> -#include "SchedulerUtils.h" +#include <android-base/thread_annotations.h> + #include "VSyncDispatch.h" namespace android::scheduler { +class VSyncTracker; + // VSyncDispatchTimerQueueEntry is a helper class representing internal state for each entry in // VSyncDispatchTimerQueue hoisted to public for unit testing. class VSyncDispatchTimerQueueEntry { @@ -38,7 +39,7 @@ public: // Valid transition: disarmed -> armed ( when scheduled ) // Valid transition: armed -> running -> disarmed ( when timer is called) // Valid transition: armed -> disarmed ( when cancelled ) - VSyncDispatchTimerQueueEntry(std::string const& name, VSyncDispatch::Callback const& fn, + VSyncDispatchTimerQueueEntry(std::string name, VSyncDispatch::Callback, nsecs_t minVsyncDistance); std::string_view name() const; @@ -47,10 +48,9 @@ public: std::optional<nsecs_t> lastExecutedVsyncTarget() const; // This moves the state from disarmed->armed and will calculate the wakeupTime. - ScheduleResult schedule(VSyncDispatch::ScheduleTiming timing, VSyncTracker& tracker, - nsecs_t now); + ScheduleResult schedule(VSyncDispatch::ScheduleTiming, VSyncTracker&, nsecs_t now); // This will update armed entries with the latest vsync information. Entry remains armed. - void update(VSyncTracker& tracker, nsecs_t now); + void update(VSyncTracker&, nsecs_t now); // This will return empty if not armed, or the next calculated wakeup time if armed. // It will not update the wakeupTime. @@ -83,11 +83,11 @@ public: void dump(std::string& result) const; private: - std::string const mName; - VSyncDispatch::Callback const mCallback; + const std::string mName; + const VSyncDispatch::Callback mCallback; VSyncDispatch::ScheduleTiming mScheduleTiming; - nsecs_t const mMinVsyncDistance; + const nsecs_t mMinVsyncDistance; struct ArmingInfo { nsecs_t mActualWakeupTime; @@ -117,19 +117,19 @@ public: // should be grouped into one wakeup. // \param[in] minVsyncDistance The minimum distance between two vsync estimates before the // vsyncs are considered the same vsync event. - explicit VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk, VSyncTracker& tracker, - nsecs_t timerSlack, nsecs_t minVsyncDistance); + VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper>, VSyncTracker&, nsecs_t timerSlack, + nsecs_t minVsyncDistance); ~VSyncDispatchTimerQueue(); - CallbackToken registerCallback(Callback const& callbackFn, std::string callbackName) final; - void unregisterCallback(CallbackToken token) final; - ScheduleResult schedule(CallbackToken token, ScheduleTiming scheduleTiming) final; - CancelResult cancel(CallbackToken token) final; - void dump(std::string& result) const final; + CallbackToken registerCallback(Callback, std::string callbackName) final; + void unregisterCallback(CallbackToken) final; + ScheduleResult schedule(CallbackToken, ScheduleTiming) final; + CancelResult cancel(CallbackToken) final; + void dump(std::string&) const final; private: - VSyncDispatchTimerQueue(VSyncDispatchTimerQueue const&) = delete; - VSyncDispatchTimerQueue& operator=(VSyncDispatchTimerQueue const&) = delete; + VSyncDispatchTimerQueue(const VSyncDispatchTimerQueue&) = delete; + VSyncDispatchTimerQueue& operator=(const VSyncDispatchTimerQueue&) = delete; using CallbackMap = std::unordered_map<CallbackToken, std::shared_ptr<VSyncDispatchTimerQueueEntry>>; @@ -153,17 +153,6 @@ private: CallbackMap mCallbacks GUARDED_BY(mMutex); nsecs_t mIntendedWakeupTime GUARDED_BY(mMutex) = kInvalidTime; - struct TraceBuffer { - static constexpr char const kTraceNamePrefix[] = "-alarm in:"; - static constexpr char const kTraceNameSeparator[] = " for vs:"; - static constexpr size_t kMaxNamePrint = 4; - static constexpr size_t kNumTsPrinted = 2; - static constexpr size_t maxlen = kMaxNamePrint + arrayLen(kTraceNamePrefix) + - arrayLen(kTraceNameSeparator) - 1 + (kNumTsPrinted * max64print); - std::array<char, maxlen> str_buffer; - void note(std::string_view name, nsecs_t in, nsecs_t vs); - } mTraceBuffer GUARDED_BY(mMutex); - // For debugging purposes nsecs_t mLastTimerCallback GUARDED_BY(mMutex) = kInvalidTime; nsecs_t mLastTimerSchedule GUARDED_BY(mMutex) = kInvalidTime; diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp index e9bd92a211..61d2fb7384 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -18,24 +18,27 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wextra" +#undef LOG_TAG +#define LOG_TAG "VSyncPredictor" + #define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 -#include "VSyncPredictor.h" + +#include <algorithm> +#include <chrono> +#include <sstream> + #include <android-base/logging.h> #include <android-base/stringprintf.h> #include <cutils/compiler.h> #include <cutils/properties.h> #include <utils/Log.h> #include <utils/Trace.h> -#include <algorithm> -#include <chrono> -#include <sstream> -#include "RefreshRateConfigs.h" -#undef LOG_TAG -#define LOG_TAG "VSyncPredictor" +#include "RefreshRateConfigs.h" +#include "VSyncPredictor.h" namespace android::scheduler { + using base::StringAppendF; static auto constexpr kMaxPercent = 100u; @@ -121,7 +124,8 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { mTimestamps[mLastTimestampIndex] = timestamp; } - if (mTimestamps.size() < kMinimumSamplesForPrediction) { + const size_t numSamples = mTimestamps.size(); + if (numSamples < kMinimumSamplesForPrediction) { mRateMap[mIdealPeriod] = {mIdealPeriod, 0}; return true; } @@ -141,36 +145,44 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { // // intercept = mean(Y) - slope * mean(X) // - std::vector<nsecs_t> vsyncTS(mTimestamps.size()); - std::vector<nsecs_t> ordinals(mTimestamps.size()); + std::vector<nsecs_t> vsyncTS(numSamples); + std::vector<nsecs_t> ordinals(numSamples); - // normalizing to the oldest timestamp cuts down on error in calculating the intercept. - auto const oldest_ts = *std::min_element(mTimestamps.begin(), mTimestamps.end()); + // Normalizing to the oldest timestamp cuts down on error in calculating the intercept. + const auto oldestTS = *std::min_element(mTimestamps.begin(), mTimestamps.end()); auto it = mRateMap.find(mIdealPeriod); auto const currentPeriod = it->second.slope; - // TODO (b/144707443): its important that there's some precision in the mean of the ordinals - // for the intercept calculation, so scale the ordinals by 1000 to continue - // fixed point calculation. Explore expanding - // scheduler::utils::calculate_mean to have a fixed point fractional part. - static constexpr int64_t kScalingFactor = 1000; - for (auto i = 0u; i < mTimestamps.size(); i++) { + // The mean of the ordinals must be precise for the intercept calculation, so scale them up for + // fixed-point arithmetic. + constexpr int64_t kScalingFactor = 1000; + + nsecs_t meanTS = 0; + nsecs_t meanOrdinal = 0; + + for (size_t i = 0; i < numSamples; i++) { traceInt64If("VSP-ts", mTimestamps[i]); - vsyncTS[i] = mTimestamps[i] - oldest_ts; - ordinals[i] = ((vsyncTS[i] + (currentPeriod / 2)) / currentPeriod) * kScalingFactor; + const auto timestamp = mTimestamps[i] - oldestTS; + vsyncTS[i] = timestamp; + meanTS += timestamp; + + const auto ordinal = (vsyncTS[i] + currentPeriod / 2) / currentPeriod * kScalingFactor; + ordinals[i] = ordinal; + meanOrdinal += ordinal; } - auto meanTS = scheduler::calculate_mean(vsyncTS); - auto meanOrdinal = scheduler::calculate_mean(ordinals); - for (size_t i = 0; i < vsyncTS.size(); i++) { + meanTS /= numSamples; + meanOrdinal /= numSamples; + + for (size_t i = 0; i < numSamples; i++) { vsyncTS[i] -= meanTS; ordinals[i] -= meanOrdinal; } - auto top = 0ll; - auto bottom = 0ll; - for (size_t i = 0; i < vsyncTS.size(); i++) { + nsecs_t top = 0; + nsecs_t bottom = 0; + for (size_t i = 0; i < numSamples; i++) { top += vsyncTS[i] * ordinals[i]; bottom += ordinals[i] * ordinals[i]; } @@ -365,4 +377,4 @@ void VSyncPredictor::dump(std::string& result) const { } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file +#pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h index 40e69443be..cfaf7d6e4d 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.h +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h @@ -16,11 +16,12 @@ #pragma once -#include <android-base/thread_annotations.h> #include <mutex> #include <unordered_map> #include <vector> -#include "SchedulerUtils.h" + +#include <android-base/thread_annotations.h> + #include "VSyncTracker.h" namespace android::scheduler { diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp index 1c9de1c452..bdcab515f2 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp @@ -18,21 +18,22 @@ #undef LOG_TAG #define LOG_TAG "VSyncReactor" //#define LOG_NDEBUG 0 -#include "VSyncReactor.h" + #include <cutils/properties.h> #include <log/log.h> #include <utils/Trace.h> + #include "../TracedOrdinal.h" -#include "TimeKeeper.h" #include "VSyncDispatch.h" +#include "VSyncReactor.h" #include "VSyncTracker.h" namespace android::scheduler { + using base::StringAppendF; VsyncController::~VsyncController() = default; -Clock::~Clock() = default; nsecs_t SystemClock::now() const { return systemTime(SYSTEM_TIME_MONOTONIC); } diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h index a9d536be28..6a1950ac77 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.h +++ b/services/surfaceflinger/Scheduler/VSyncReactor.h @@ -16,14 +16,18 @@ #pragma once -#include <android-base/thread_annotations.h> -#include <ui/FenceTime.h> #include <memory> #include <mutex> #include <unordered_map> #include <vector> -#include "TimeKeeper.h" + +#include <android-base/thread_annotations.h> +#include <ui/FenceTime.h> + +#include <scheduler/TimeKeeper.h> + #include "VsyncController.h" + namespace android::scheduler { class Clock; diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp index 77d1223aeb..e611658bfd 100644 --- a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp +++ b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp @@ -15,10 +15,10 @@ */ #include <scheduler/Fps.h> +#include <scheduler/Timer.h> #include "VsyncSchedule.h" -#include "Timer.h" #include "VSyncDispatchTimerQueue.h" #include "VSyncPredictor.h" #include "VSyncReactor.h" diff --git a/services/surfaceflinger/Scheduler/TimeKeeper.h b/services/surfaceflinger/Scheduler/include/scheduler/TimeKeeper.h index 40dd8410a3..319390bfab 100644 --- a/services/surfaceflinger/Scheduler/TimeKeeper.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/TimeKeeper.h @@ -16,14 +16,17 @@ #pragma once -#include <utils/Timers.h> #include <functional> +#include <string> + +#include <utils/Timers.h> namespace android::scheduler { class Clock { public: virtual ~Clock(); + /* * Returns the SYSTEM_TIME_MONOTONIC, used by testing infra to stub time. */ @@ -31,8 +34,9 @@ public: protected: Clock() = default; - Clock(Clock const&) = delete; - Clock& operator=(Clock const&) = delete; + + Clock(const Clock&) = delete; + Clock& operator=(const Clock&) = delete; }; /* @@ -46,19 +50,20 @@ public: * Arms callback to fired when time is current based on CLOCK_MONOTONIC * There is only one timer, and subsequent calls will reset the callback function and the time. */ - virtual void alarmAt(std::function<void()> const& callback, nsecs_t time) = 0; + virtual void alarmAt(std::function<void()>, nsecs_t time) = 0; /* * Cancels an existing pending callback */ virtual void alarmCancel() = 0; - virtual void dump(std::string& result) const = 0; + virtual void dump(std::string&) const = 0; protected: - TimeKeeper(TimeKeeper const&) = delete; - TimeKeeper& operator=(TimeKeeper const&) = delete; TimeKeeper() = default; + + TimeKeeper(const TimeKeeper&) = delete; + TimeKeeper& operator=(const TimeKeeper&) = delete; }; } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/Timer.h b/services/surfaceflinger/Scheduler/include/scheduler/Timer.h index eb659543eb..58ad6cb991 100644 --- a/services/surfaceflinger/Scheduler/Timer.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/Timer.h @@ -16,25 +16,30 @@ #pragma once -#include "TimeKeeper.h" - -#include <android-base/thread_annotations.h> #include <array> +#include <functional> +#include <mutex> #include <thread> +#include <android-base/thread_annotations.h> + +#include <scheduler/TimeKeeper.h> + namespace android::scheduler { class Timer : public TimeKeeper { public: Timer(); ~Timer(); + nsecs_t now() const final; // NB: alarmAt and alarmCancel are threadsafe; with the last-returning function being effectual // Most users will want to serialize thes calls so as to be aware of the timer state. - void alarmAt(std::function<void()> const& cb, nsecs_t time) final; + void alarmAt(std::function<void()>, nsecs_t time) final; void alarmCancel() final; - void dump(std::string& result) const final; + + void dump(std::string&) const final; protected: // For unit testing @@ -54,7 +59,7 @@ private: void reset() EXCLUDES(mMutex); void cleanup() REQUIRES(mMutex); - void setDebugState(DebugState state) EXCLUDES(mMutex); + void setDebugState(DebugState) EXCLUDES(mMutex); int mTimerFd = -1; diff --git a/services/surfaceflinger/Scheduler/Timer.cpp b/services/surfaceflinger/Scheduler/src/Timer.cpp index 68f9321c79..a4cf57fbaa 100644 --- a/services/surfaceflinger/Scheduler/Timer.cpp +++ b/services/surfaceflinger/Scheduler/src/Timer.cpp @@ -16,7 +16,6 @@ #undef LOG_TAG #define LOG_TAG "SchedulerTimer" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS #include <chrono> #include <cstdint> @@ -25,19 +24,20 @@ #include <sys/timerfd.h> #include <sys/unistd.h> -#include <android-base/stringprintf.h> +#include <ftl/concat.h> #include <ftl/enum.h> #include <log/log.h> #include <utils/Trace.h> -#include "SchedulerUtils.h" -#include "Timer.h" +#include <scheduler/Timer.h> namespace android::scheduler { -using base::StringAppendF; -static constexpr size_t kReadPipe = 0; -static constexpr size_t kWritePipe = 1; +constexpr size_t kReadPipe = 0; +constexpr size_t kWritePipe = 1; + +Clock::~Clock() = default; +TimeKeeper::~TimeKeeper() = default; Timer::Timer() { reset(); @@ -106,13 +106,13 @@ nsecs_t Timer::now() const { return systemTime(SYSTEM_TIME_MONOTONIC); } -void Timer::alarmAt(std::function<void()> const& cb, nsecs_t time) { +void Timer::alarmAt(std::function<void()> callback, nsecs_t time) { std::lock_guard lock(mMutex); using namespace std::literals; static constexpr int ns_per_s = std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count(); - mCallback = cb; + mCallback = std::move(callback); mExpectingCallback = true; struct itimerspec old_timer; @@ -180,9 +180,6 @@ bool Timer::dispatch() { } uint64_t iteration = 0; - char const traceNamePrefix[] = "TimerIteration #"; - static constexpr size_t maxlen = arrayLen(traceNamePrefix) + max64print; - std::array<char, maxlen> str_buffer; while (true) { setDebugState(DebugState::Waiting); @@ -191,9 +188,8 @@ bool Timer::dispatch() { setDebugState(DebugState::Running); if (ATRACE_ENABLED()) { - snprintf(str_buffer.data(), str_buffer.size(), "%s%" PRIu64, traceNamePrefix, - iteration++); - ATRACE_NAME(str_buffer.data()); + ftl::Concat trace("TimerIteration #", iteration++); + ATRACE_NAME(trace.c_str()); } if (nfds == -1) { @@ -237,7 +233,9 @@ void Timer::setDebugState(DebugState state) { void Timer::dump(std::string& result) const { std::lock_guard lock(mMutex); - StringAppendF(&result, "\t\tDebugState: %s\n", ftl::enum_string(mDebugState).c_str()); + result.append("\t\tDebugState: "); + result.append(ftl::enum_string(mDebugState)); + result.push_back('\n'); } } // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/AsyncCallRecorder.h b/services/surfaceflinger/Scheduler/tests/AsyncCallRecorder.h index 8bed766262..57f0dab200 100644 --- a/services/surfaceflinger/tests/unittests/AsyncCallRecorder.h +++ b/services/surfaceflinger/Scheduler/tests/AsyncCallRecorder.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/services/surfaceflinger/tests/unittests/TimerTest.cpp b/services/surfaceflinger/Scheduler/tests/TimerTest.cpp index 0a3639db90..47d968c94e 100644 --- a/services/surfaceflinger/tests/unittests/TimerTest.cpp +++ b/services/surfaceflinger/Scheduler/tests/TimerTest.cpp @@ -14,15 +14,13 @@ * limitations under the License. */ -#include "AsyncCallRecorder.h" -#include "Scheduler/TimeKeeper.h" -#include "Scheduler/Timer.h" - #include <gmock/gmock.h> #include <gtest/gtest.h> -using namespace testing; -using namespace std::literals; +#include <scheduler/TimeKeeper.h> +#include <scheduler/Timer.h> + +#include "AsyncCallRecorder.h" namespace android::scheduler { @@ -35,7 +33,7 @@ public: }; struct TimerTest : testing::Test { - static constexpr int mIterations = 20; + static constexpr int kIterations = 20; AsyncCallRecorder<void (*)()> mCallbackRecorder; TestableTimer mTimer; @@ -44,17 +42,17 @@ struct TimerTest : testing::Test { }; TEST_F(TimerTest, callsCallbackIfScheduledInPast) { - for (int i = 0; i < mIterations; i++) { - mTimer.alarmAt(std::bind(&TimerTest::timerCallback, this), systemTime() - 10'000'00); + for (int i = 0; i < kIterations; i++) { + mTimer.alarmAt(std::bind(&TimerTest::timerCallback, this), systemTime() - 1'000'000); EXPECT_TRUE(mCallbackRecorder.waitForCall().has_value()); EXPECT_FALSE(mCallbackRecorder.waitForUnexpectedCall().has_value()); } } TEST_F(TimerTest, recoversAfterEpollError) { - for (int i = 0; i < mIterations; i++) { + for (int i = 0; i < kIterations; i++) { mTimer.makeEpollError(); - mTimer.alarmAt(std::bind(&TimerTest::timerCallback, this), systemTime() - 10'000'00); + mTimer.alarmAt(std::bind(&TimerTest::timerCallback, this), systemTime() - 1'000'000); EXPECT_TRUE(mCallbackRecorder.waitForCall().has_value()); EXPECT_FALSE(mCallbackRecorder.waitForUnexpectedCall().has_value()); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 0bb0aa8b7e..ea5025fc20 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -65,6 +65,7 @@ #include <private/gui/SyncFeatures.h> #include <processgroup/processgroup.h> #include <renderengine/RenderEngine.h> +#include <renderengine/impl/ExternalTexture.h> #include <sys/types.h> #include <ui/ColorSpace.h> #include <ui/DataspaceUtils.h> @@ -504,10 +505,8 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI enableLatchUnsignaledConfig = getLatchUnsignaledConfig(); - mTransactionTracingEnabled = - !mIsUserBuild && property_get_bool("debug.sf.enable_transaction_tracing", true); - if (mTransactionTracingEnabled) { - mTransactionTracing.enable(); + if (!mIsUserBuild && base::GetBoolProperty("debug.sf.enable_transaction_tracing"s, true)) { + mTransactionTracing.emplace(); } } @@ -3769,8 +3768,8 @@ bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactio } } - if (mTransactionTracingEnabled) { - mTransactionTracing.addCommittedTransactions(transactions, vsyncId); + if (mTransactionTracing) { + mTransactionTracing->addCommittedTransactions(transactions, vsyncId); } return needsTraversal; } @@ -4030,8 +4029,8 @@ status_t SurfaceFlinger::setTransactionState( mBufferCountTracker.increment(state.surface->localBinder()); }); - if (mTransactionTracingEnabled) { - mTransactionTracing.addQueuedTransaction(state); + if (mTransactionTracing) { + mTransactionTracing->addQueuedTransaction(state); } queueTransaction(state); @@ -4521,10 +4520,13 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime } } - if (what & layer_state_t::eBufferChanged && - layer->setBuffer(*s.bufferData, postTime, desiredPresentTime, isAutoTimestamp, - dequeueBufferTimestamp, frameTimelineInfo)) { - flags |= eTraversalNeeded; + if (what & layer_state_t::eBufferChanged) { + std::shared_ptr<renderengine::ExternalTexture> buffer = + getExternalTextureFromBufferData(*s.bufferData, layer->getDebugName()); + if (layer->setBuffer(buffer, *s.bufferData, postTime, desiredPresentTime, isAutoTimestamp, + dequeueBufferTimestamp, frameTimelineInfo)) { + flags |= eTraversalNeeded; + } } else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { layer->setFrameTimelineVsyncForBufferlessTransaction(frameTimelineInfo, postTime); } @@ -4564,9 +4566,9 @@ status_t SurfaceFlinger::mirrorLayer(const LayerCreationArgs& args, } *outLayerId = mirrorLayer->sequence; - if (mTransactionTracingEnabled) { - mTransactionTracing.onMirrorLayerAdded((*outHandle)->localBinder(), mirrorLayer->sequence, - args.name, mirrorFrom->sequence); + if (mTransactionTracing) { + mTransactionTracing->onMirrorLayerAdded((*outHandle)->localBinder(), mirrorLayer->sequence, + args.name, mirrorFrom->sequence); } return addClientLayer(args.client, *outHandle, mirrorLayer /* layer */, nullptr /* parent */, false /* addAsRoot */, nullptr /* outTransformHint */); @@ -4626,9 +4628,9 @@ status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, sp<IBinder>* outHa if (parentSp != nullptr) { parentId = parentSp->getSequence(); } - if (mTransactionTracingEnabled) { - mTransactionTracing.onLayerAdded((*outHandle)->localBinder(), layer->sequence, args.name, - args.flags, parentId); + if (mTransactionTracing) { + mTransactionTracing->onLayerAdded((*outHandle)->localBinder(), layer->sequence, args.name, + args.flags, parentId); } result = addClientLayer(args.client, *outHandle, layer, parent, addToRoot, outTransformHint); @@ -4718,8 +4720,8 @@ void SurfaceFlinger::onHandleDestroyed(BBinder* handle, sp<Layer>& layer) { markLayerPendingRemovalLocked(layer); mBufferCountTracker.remove(handle); layer.clear(); - if (mTransactionTracingEnabled) { - mTransactionTracing.onHandleRemoved(handle); + if (mTransactionTracing) { + mTransactionTracing->onHandleRemoved(handle); } } @@ -4954,7 +4956,9 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { status_t SurfaceFlinger::dumpCritical(int fd, const DumpArgs&, bool asProto) { if (asProto) { mLayerTracing.writeToFile(); - mTransactionTracing.writeToFile(); + if (mTransactionTracing) { + mTransactionTracing->writeToFile(); + } } return doDump(fd, DumpArgs(), asProto); @@ -5351,9 +5355,15 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co * Tracing state */ mLayerTracing.dump(result); - result.append("\n"); - mTransactionTracing.dump(result); - result.append("\n"); + + result.append("\nTransaction tracing: "); + if (mTransactionTracing) { + result.append("enabled\n"); + mTransactionTracing->dump(result); + } else { + result.append("disabled\n"); + } + result.push_back('\n'); /* * HWC layer minidump @@ -6034,15 +6044,17 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r return NO_ERROR; } case 1041: { // Transaction tracing - if (data.readInt32()) { - // Transaction tracing is always running but allow the user to temporarily - // increase the buffer when actively debugging. - mTransactionTracing.setBufferSize( - TransactionTracing::ACTIVE_TRACING_BUFFER_SIZE); - } else { - mTransactionTracing.setBufferSize( - TransactionTracing::CONTINUOUS_TRACING_BUFFER_SIZE); - mTransactionTracing.writeToFile(); + if (mTransactionTracing) { + if (data.readInt32()) { + // Transaction tracing is always running but allow the user to temporarily + // increase the buffer when actively debugging. + mTransactionTracing->setBufferSize( + TransactionTracing::ACTIVE_TRACING_BUFFER_SIZE); + } else { + mTransactionTracing->setBufferSize( + TransactionTracing::CONTINUOUS_TRACING_BUFFER_SIZE); + mTransactionTracing->writeToFile(); + } } reply->writeInt32(NO_ERROR); return NO_ERROR; @@ -6491,9 +6503,10 @@ std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::captureScre const status_t bufferStatus = buffer->initCheck(); LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureScreenCommon: Buffer failed to allocate: %d", bufferStatus); - const auto texture = std::make_shared< - renderengine::ExternalTexture>(buffer, getRenderEngine(), - renderengine::ExternalTexture::Usage::WRITEABLE); + const std::shared_ptr<renderengine::ExternalTexture> texture = std::make_shared< + renderengine::impl::ExternalTexture>(buffer, getRenderEngine(), + renderengine::impl::ExternalTexture::Usage:: + WRITEABLE); return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, texture, false /* regionSampling */, grayscale, captureListener); } @@ -6570,7 +6583,7 @@ std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::renderScree captureResults.capturedSecureLayers || (layer->isVisible() && layer->isSecure()); }); - const bool useProtected = buffer->getBuffer()->getUsage() & GRALLOC_USAGE_PROTECTED; + const bool useProtected = buffer->getUsage() & GRALLOC_USAGE_PROTECTED; // We allow the system server to take screenshots of secure layers for // use in situations like the Screen-rotation animation and place @@ -6883,8 +6896,8 @@ void SurfaceFlinger::onLayerDestroyed(Layer* layer) { if (!layer->isRemovedFromCurrentState()) { mScheduler->deregisterLayer(layer); } - if (mTransactionTracingEnabled) { - mTransactionTracing.onLayerRemoved(layer->getSequence()); + if (mTransactionTracing) { + mTransactionTracing->onLayerRemoved(layer->getSequence()); } } @@ -7192,6 +7205,36 @@ status_t SurfaceFlinger::removeWindowInfosListener( return NO_ERROR; } +std::shared_ptr<renderengine::ExternalTexture> SurfaceFlinger::getExternalTextureFromBufferData( + const BufferData& bufferData, const char* layerName) const { + bool cacheIdChanged = bufferData.flags.test(BufferData::BufferDataChange::cachedBufferChanged); + bool bufferSizeExceedsLimit = false; + std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr; + if (cacheIdChanged && bufferData.buffer != nullptr) { + bufferSizeExceedsLimit = exceedsMaxRenderTargetSize(bufferData.buffer->getWidth(), + bufferData.buffer->getHeight()); + if (!bufferSizeExceedsLimit) { + ClientCache::getInstance().add(bufferData.cachedBuffer, bufferData.buffer); + buffer = ClientCache::getInstance().get(bufferData.cachedBuffer); + } + } else if (cacheIdChanged) { + buffer = ClientCache::getInstance().get(bufferData.cachedBuffer); + } else if (bufferData.buffer != nullptr) { + bufferSizeExceedsLimit = exceedsMaxRenderTargetSize(bufferData.buffer->getWidth(), + bufferData.buffer->getHeight()); + if (!bufferSizeExceedsLimit) { + buffer = std::make_shared< + renderengine::impl::ExternalTexture>(bufferData.buffer, getRenderEngine(), + renderengine::impl::ExternalTexture:: + Usage::READABLE); + } + } + ALOGE_IF(bufferSizeExceedsLimit, + "Attempted to create an ExternalTexture for layer %s that exceeds render target size " + "limit.", + layerName); + return buffer; +} } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 168b0cd5bf..8ca9982b98 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -326,6 +326,9 @@ protected: virtual void processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState&) REQUIRES(mStateLock); + virtual std::shared_ptr<renderengine::ExternalTexture> getExternalTextureFromBufferData( + const BufferData& bufferData, const char* layerName) const; + // Returns true if any display matches a `bool(const DisplayDevice&)` predicate. template <typename Predicate> bool hasDisplay(Predicate p) const REQUIRES(mStateLock) { @@ -1196,8 +1199,7 @@ private: LayerTracing mLayerTracing{*this}; bool mLayerTracingEnabled = false; - TransactionTracing mTransactionTracing; - bool mTransactionTracingEnabled = false; + std::optional<TransactionTracing> mTransactionTracing; std::atomic<bool> mTracingEnabledChanged = false; const std::shared_ptr<TimeStats> mTimeStats; diff --git a/services/surfaceflinger/TracedOrdinal.h b/services/surfaceflinger/TracedOrdinal.h index eee4bec344..558b3be273 100644 --- a/services/surfaceflinger/TracedOrdinal.h +++ b/services/surfaceflinger/TracedOrdinal.h @@ -15,12 +15,15 @@ */ #pragma once -#include <android-base/stringprintf.h> -#include <cutils/compiler.h> -#include <utils/Trace.h> + +#include <chrono> #include <cmath> +#include <functional> #include <string> +#include <cutils/compiler.h> +#include <utils/Trace.h> + namespace std { template <class Rep, class Period> bool signbit(std::chrono::duration<Rep, Period> v) { @@ -75,7 +78,7 @@ private: } if (mNameNegative.empty()) { - mNameNegative = base::StringPrintf("%sNegative", mName.c_str()); + mNameNegative = mName + "Negative"; } if (!std::signbit(mData)) { diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp index 849de22a41..a91698fb79 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp @@ -31,6 +31,7 @@ proto::TransactionState TransactionProtoParser::toProto(const TransactionState& proto.set_vsync_id(t.frameTimelineInfo.vsyncId); proto.set_input_event_id(t.frameTimelineInfo.inputEventId); proto.set_post_time(t.postTime); + proto.set_transaction_id(t.id); for (auto& layerState : t.states) { proto.mutable_layer_changes()->Add(std::move(toProto(layerState.state, getLayerId))); @@ -52,6 +53,9 @@ proto::TransactionState TransactionProtoParser::toProto( bufferProto->set_buffer_id(state.bufferId); bufferProto->set_width(state.bufferWidth); bufferProto->set_height(state.bufferHeight); + bufferProto->set_pixel_format( + static_cast<proto::LayerState_BufferData_PixelFormat>(state.pixelFormat)); + bufferProto->set_usage(state.bufferUsage); } layerProto.set_has_sideband_stream(state.hasSidebandStream); layerProto.set_layer_id(state.layerId); @@ -136,6 +140,9 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer, bufferProto->set_buffer_id(layer.bufferData->getId()); bufferProto->set_width(layer.bufferData->getWidth()); bufferProto->set_height(layer.bufferData->getHeight()); + bufferProto->set_pixel_format(static_cast<proto::LayerState_BufferData_PixelFormat>( + layer.bufferData->getPixelFormat())); + bufferProto->set_usage(layer.bufferData->getUsage()); } bufferProto->set_frame_number(layer.bufferData->frameNumber); bufferProto->set_flags(layer.bufferData->flags.get()); @@ -169,6 +176,7 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer, ? getLayerId(layer.relativeLayerSurfaceControl->getHandle()) : -1; proto.set_relative_parent_id(layerId); + proto.set_z(layer.z); } if (layer.what & layer_state_t::eInputInfoChanged) { @@ -291,10 +299,13 @@ TransactionState TransactionProtoParser::fromProto(const proto::TransactionState t.frameTimelineInfo.vsyncId = proto.vsync_id(); t.frameTimelineInfo.inputEventId = proto.input_event_id(); t.postTime = proto.post_time(); + t.id = proto.transaction_id(); + int32_t layerCount = proto.layer_changes_size(); t.states.reserve(static_cast<size_t>(layerCount)); for (int i = 0; i < layerCount; i++) { ComposerState s; + s.state.what = 0; fromProto(proto.layer_changes(i), getLayerHandle, s.state); t.states.add(s); } @@ -316,27 +327,31 @@ void TransactionProtoParser::fromProto(const proto::LayerCreationArgs& proto, outArgs.mirrorFromId = proto.mirror_from_id(); } -void TransactionProtoParser::fromProto(const proto::LayerState& proto, - LayerIdToHandleFn getLayerHandle, - TracingLayerState& outState) { - fromProto(proto, getLayerHandle, static_cast<layer_state_t&>(outState)); - if (proto.what() & layer_state_t::eReparent) { +void TransactionProtoParser::mergeFromProto(const proto::LayerState& proto, + LayerIdToHandleFn getLayerHandle, + TracingLayerState& outState) { + layer_state_t state; + fromProto(proto, getLayerHandle, state); + outState.merge(state); + + if (state.what & layer_state_t::eReparent) { outState.parentId = proto.parent_id(); - outState.args.parentId = outState.parentId; } - if (proto.what() & layer_state_t::eRelativeLayerChanged) { + if (state.what & layer_state_t::eRelativeLayerChanged) { outState.relativeParentId = proto.relative_parent_id(); } - if (proto.what() & layer_state_t::eInputInfoChanged) { + if (state.what & layer_state_t::eInputInfoChanged) { outState.inputCropId = proto.window_info_handle().crop_layer_id(); } - if (proto.what() & layer_state_t::eBufferChanged) { + if (state.what & layer_state_t::eBufferChanged) { const proto::LayerState_BufferData& bufferProto = proto.buffer_data(); outState.bufferId = bufferProto.buffer_id(); outState.bufferWidth = bufferProto.width(); outState.bufferHeight = bufferProto.height(); + outState.pixelFormat = bufferProto.pixel_format(); + outState.bufferUsage = bufferProto.usage(); } - if (proto.what() & layer_state_t::eSidebandStreamChanged) { + if (state.what & layer_state_t::eSidebandStreamChanged) { outState.hasSidebandStream = proto.has_sideband_stream(); } } @@ -432,15 +447,24 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, if ((proto.what() & layer_state_t::eReparent) && (getLayerHandle != nullptr)) { int32_t layerId = proto.parent_id(); - layer.parentSurfaceControlForChild = - new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId), - nullptr, layerId); + if (layerId == -1) { + layer.parentSurfaceControlForChild = nullptr; + } else { + layer.parentSurfaceControlForChild = + new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId), + nullptr, layerId); + } } - if ((proto.what() & layer_state_t::eRelativeLayerChanged) && (getLayerHandle != nullptr)) { + if (proto.what() & layer_state_t::eRelativeLayerChanged) { int32_t layerId = proto.relative_parent_id(); - layer.relativeLayerSurfaceControl = - new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId), - nullptr, layerId); + if (layerId == -1) { + layer.relativeLayerSurfaceControl = nullptr; + } else if (getLayerHandle != nullptr) { + layer.relativeLayerSurfaceControl = + new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId), + nullptr, layerId); + } + layer.z = proto.z(); } if ((proto.what() & layer_state_t::eInputInfoChanged) && proto.has_window_info_handle()) { diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h index b78d3d96da..d589936642 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.h +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h @@ -34,6 +34,8 @@ struct TracingLayerState : layer_state_t { uint64_t bufferId; uint32_t bufferHeight; uint32_t bufferWidth; + int32_t pixelFormat; + uint64_t bufferUsage; bool hasSidebandStream; int32_t parentId; int32_t relativeParentId; @@ -58,8 +60,8 @@ public: static TransactionState fromProto(const proto::TransactionState&, LayerIdToHandleFn getLayerHandleFn, DisplayIdToHandleFn getDisplayHandleFn); - static void fromProto(const proto::LayerState&, LayerIdToHandleFn getLayerHandleFn, - TracingLayerState& outState); + static void mergeFromProto(const proto::LayerState&, LayerIdToHandleFn getLayerHandleFn, + TracingLayerState& outState); static void fromProto(const proto::LayerCreationArgs&, TracingLayerCreationArgs& outArgs); private: diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp index b5966d5837..5136295592 100644 --- a/services/surfaceflinger/Tracing/TransactionTracing.cpp +++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp @@ -23,35 +23,22 @@ #include <utils/SystemClock.h> #include <utils/Trace.h> -#include "RingBuffer.h" #include "TransactionTracing.h" namespace android { TransactionTracing::TransactionTracing() { - mBuffer = std::make_unique< - RingBuffer<proto::TransactionTraceFile, proto::TransactionTraceEntry>>(); -} - -TransactionTracing::~TransactionTracing() = default; - -bool TransactionTracing::enable() { std::scoped_lock lock(mTraceLock); - if (mEnabled) { - return false; - } - mBuffer->setSize(mBufferSizeInBytes); + + mBuffer.setSize(mBufferSizeInBytes); mStartingTimestamp = systemTime(); - mEnabled = true; { std::scoped_lock lock(mMainThreadLock); - mDone = false; mThread = std::thread(&TransactionTracing::loop, this); } - return true; } -bool TransactionTracing::disable() { +TransactionTracing::~TransactionTracing() { std::thread thread; { std::scoped_lock lock(mMainThreadLock); @@ -63,43 +50,20 @@ bool TransactionTracing::disable() { thread.join(); } - std::scoped_lock lock(mTraceLock); - if (!mEnabled) { - return false; - } - mEnabled = false; - - writeToFileLocked(); - mBuffer->reset(); - mQueuedTransactions.clear(); - mStartingStates.clear(); - mLayerHandles.clear(); - return true; -} - -bool TransactionTracing::isEnabled() const { - std::scoped_lock lock(mTraceLock); - return mEnabled; + writeToFile(); } status_t TransactionTracing::writeToFile() { std::scoped_lock lock(mTraceLock); - if (!mEnabled) { - return STATUS_OK; - } - return writeToFileLocked(); -} - -status_t TransactionTracing::writeToFileLocked() { proto::TransactionTraceFile fileProto = createTraceFileProto(); addStartingStateToProtoLocked(fileProto); - return mBuffer->writeToFile(fileProto, FILE_NAME); + return mBuffer.writeToFile(fileProto, FILE_NAME); } void TransactionTracing::setBufferSize(size_t bufferSizeInBytes) { std::scoped_lock lock(mTraceLock); mBufferSizeInBytes = bufferSizeInBytes; - mBuffer->setSize(mBufferSizeInBytes); + mBuffer.setSize(mBufferSizeInBytes); } proto::TransactionTraceFile TransactionTracing::createTraceFileProto() const { @@ -111,21 +75,16 @@ proto::TransactionTraceFile TransactionTracing::createTraceFileProto() const { void TransactionTracing::dump(std::string& result) const { std::scoped_lock lock(mTraceLock); - base::StringAppendF(&result, "Transaction tracing state: %s\n", - mEnabled ? "enabled" : "disabled"); base::StringAppendF(&result, " queued transactions=%zu created layers=%zu handles=%zu states=%zu\n", mQueuedTransactions.size(), mCreatedLayers.size(), mLayerHandles.size(), mStartingStates.size()); - mBuffer->dump(result); + mBuffer.dump(result); } void TransactionTracing::addQueuedTransaction(const TransactionState& transaction) { std::scoped_lock lock(mTraceLock); ATRACE_CALL(); - if (!mEnabled) { - return; - } mQueuedTransactions[transaction.id] = TransactionProtoParser::toProto(transaction, std::bind(&TransactionTracing::getLayerIdLocked, this, @@ -206,10 +165,17 @@ void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& comm std::string serializedProto; entryProto.SerializeToString(&serializedProto); entryProto.Clear(); - std::vector<std::string> entries = mBuffer->emplace(std::move(serializedProto)); + std::vector<std::string> entries = mBuffer.emplace(std::move(serializedProto)); removedEntries.reserve(removedEntries.size() + entries.size()); removedEntries.insert(removedEntries.end(), std::make_move_iterator(entries.begin()), std::make_move_iterator(entries.end())); + + entryProto.mutable_removed_layer_handles()->Reserve( + static_cast<int32_t>(mRemovedLayerHandles.size())); + for (auto& handle : mRemovedLayerHandles) { + entryProto.mutable_removed_layer_handles()->Add(handle); + } + mRemovedLayerHandles.clear(); } proto::TransactionTraceEntry removedEntryProto; @@ -229,10 +195,10 @@ void TransactionTracing::flush(int64_t vsyncId) { base::ScopedLockAssertion assumeLocked(mTraceLock); mTransactionsAddedToBufferCv.wait(lock, [&]() REQUIRES(mTraceLock) { proto::TransactionTraceEntry entry; - if (mBuffer->used() > 0) { - entry.ParseFromString(mBuffer->back()); + if (mBuffer.used() > 0) { + entry.ParseFromString(mBuffer.back()); } - return mBuffer->used() > 0 && entry.vsync_id() >= vsyncId; + return mBuffer.used() > 0 && entry.vsync_id() >= vsyncId; }); } @@ -267,7 +233,14 @@ void TransactionTracing::onLayerRemoved(int32_t layerId) { void TransactionTracing::onHandleRemoved(BBinder* layerHandle) { std::scoped_lock lock(mTraceLock); - mLayerHandles.erase(layerHandle); + auto it = mLayerHandles.find(layerHandle); + if (it == mLayerHandles.end()) { + ALOGW("handle not found. %p", layerHandle); + return; + } + + mRemovedLayerHandles.push_back(it->second); + mLayerHandles.erase(it); } void TransactionTracing::tryPushToTracingThread() { @@ -318,7 +291,7 @@ void TransactionTracing::updateStartingStateLocked( ALOGW("Could not find layer id %d", layerState.layer_id()); continue; } - TransactionProtoParser::fromProto(layerState, nullptr, it->second); + TransactionProtoParser::mergeFromProto(layerState, nullptr, it->second); } } @@ -352,7 +325,7 @@ proto::TransactionTraceFile TransactionTracing::writeToProto() { std::scoped_lock<std::mutex> lock(mTraceLock); proto::TransactionTraceFile proto = createTraceFileProto(); addStartingStateToProtoLocked(proto); - mBuffer->writeToProto(proto); + mBuffer.writeToProto(proto); return proto; } diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h index 26a37586dc..d5d98cee9d 100644 --- a/services/surfaceflinger/Tracing/TransactionTracing.h +++ b/services/surfaceflinger/Tracing/TransactionTracing.h @@ -25,17 +25,16 @@ #include <mutex> #include <thread> +#include "RingBuffer.h" #include "TransactionProtoParser.h" using namespace android::surfaceflinger; namespace android { -template <typename FileProto, typename EntryProto> -class RingBuffer; - class SurfaceFlinger; class TransactionTracingTest; + /* * Records all committed transactions into a ring bufffer. * @@ -54,10 +53,6 @@ public: TransactionTracing(); ~TransactionTracing(); - bool enable(); - bool disable(); - bool isEnabled() const; - void addQueuedTransaction(const TransactionState&); void addCommittedTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId); status_t writeToFile(); @@ -78,8 +73,7 @@ private: static constexpr auto FILE_NAME = "/data/misc/wmtrace/transactions_trace.winscope"; mutable std::mutex mTraceLock; - bool mEnabled GUARDED_BY(mTraceLock) = false; - std::unique_ptr<RingBuffer<proto::TransactionTraceFile, proto::TransactionTraceEntry>> mBuffer + RingBuffer<proto::TransactionTraceFile, proto::TransactionTraceEntry> mBuffer GUARDED_BY(mTraceLock); size_t mBufferSizeInBytes GUARDED_BY(mTraceLock) = CONTINUOUS_TRACING_BUFFER_SIZE; std::unordered_map<uint64_t, proto::TransactionState> mQueuedTransactions @@ -88,6 +82,7 @@ private: std::vector<proto::LayerCreationArgs> mCreatedLayers GUARDED_BY(mTraceLock); std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */> mLayerHandles GUARDED_BY(mTraceLock); + std::vector<int32_t /* layerId */> mRemovedLayerHandles GUARDED_BY(mTraceLock); std::map<int32_t /* layerId */, TracingLayerState> mStartingStates GUARDED_BY(mTraceLock); // We do not want main thread to block so main thread will try to acquire mMainThreadLock, @@ -116,7 +111,6 @@ private: void tryPushToTracingThread() EXCLUDES(mMainThreadLock); void addStartingStateToProtoLocked(proto::TransactionTraceFile& proto) REQUIRES(mTraceLock); void updateStartingStateLocked(const proto::TransactionTraceEntry& entry) REQUIRES(mTraceLock); - status_t writeToFileLocked() REQUIRES(mTraceLock); // TEST // Wait until all the committed transactions for the specified vsync id are added to the buffer. diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto index 4529905566..2e9e659880 100644 --- a/services/surfaceflinger/layerproto/layers.proto +++ b/services/surfaceflinger/layerproto/layers.proto @@ -155,6 +155,7 @@ message ActiveBufferProto { uint32 height = 2; uint32 stride = 3; int32 format = 4; + uint64 usage = 5; } message BarrierLayerProto { diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto index e31b502efc..9b076bd282 100644 --- a/services/surfaceflinger/layerproto/transactions.proto +++ b/services/surfaceflinger/layerproto/transactions.proto @@ -46,6 +46,7 @@ message TransactionTraceEntry { repeated int32 removed_layers = 5; repeated DisplayState added_displays = 6; repeated int32 removed_displays = 7; + repeated int32 removed_layer_handles = 8; } message LayerCreationArgs { @@ -62,8 +63,9 @@ message TransactionState { int64 vsync_id = 3; int32 input_event_id = 4; int64 post_time = 5; - repeated LayerState layer_changes = 6; - repeated DisplayState display_changes = 7; + uint64 transaction_id = 6; + repeated LayerState layer_changes = 7; + repeated DisplayState display_changes = 8; } // Keep insync with layer_state_t @@ -78,28 +80,35 @@ message LayerState { eLayerChanged = 0x00000002; eSizeChanged = 0x00000004; eAlphaChanged = 0x00000008; + eMatrixChanged = 0x00000010; eTransparentRegionChanged = 0x00000020; eFlagsChanged = 0x00000040; eLayerStackChanged = 0x00000080; + eReleaseBufferListenerChanged = 0x00000400; eShadowRadiusChanged = 0x00000800; + eLayerCreated = 0x00001000; eBufferCropChanged = 0x00002000; eRelativeLayerChanged = 0x00004000; eReparent = 0x00008000; + eColorChanged = 0x00010000; eDestroySurface = 0x00020000; eTransformChanged = 0x00040000; eTransformToDisplayInverseChanged = 0x00080000; + eCropChanged = 0x00100000; eBufferChanged = 0x00200000; eAcquireFenceChanged = 0x00400000; eDataspaceChanged = 0x00800000; + eHdrMetadataChanged = 0x01000000; eSurfaceDamageRegionChanged = 0x02000000; eApiChanged = 0x04000000; eSidebandStreamChanged = 0x08000000; + eColorTransformChanged = 0x10000000; eHasListenerCallbacksChanged = 0x20000000; eInputInfoChanged = 0x40000000; @@ -139,6 +148,7 @@ message LayerState { eLayerSkipScreenshot = 0x40; eLayerSecure = 0x80; eEnableBackpressure = 0x100; + eLayerIsDisplayDecoration = 0x200; }; uint32 flags = 9; uint32 mask = 10; @@ -181,6 +191,26 @@ message LayerState { } uint32 flags = 5; uint64 cached_buffer_id = 6; + + enum PixelFormat { + PIXEL_FORMAT_UNKNOWN = 0; + PIXEL_FORMAT_CUSTOM = -4; + PIXEL_FORMAT_TRANSLUCENT = -3; + PIXEL_FORMAT_TRANSPARENT = -2; + PIXEL_FORMAT_OPAQUE = -1; + PIXEL_FORMAT_RGBA_8888 = 1; + PIXEL_FORMAT_RGBX_8888 = 2; + PIXEL_FORMAT_RGB_888 = 3; + PIXEL_FORMAT_RGB_565 = 4; + PIXEL_FORMAT_BGRA_8888 = 5; + PIXEL_FORMAT_RGBA_5551 = 6; + PIXEL_FORMAT_RGBA_4444 = 7; + PIXEL_FORMAT_RGBA_FP16 = 22; + PIXEL_FORMAT_RGBA_1010102 = 43; + PIXEL_FORMAT_R_8 = 0x38; + } + PixelFormat pixel_format = 7; + uint64 usage = 8; } BufferData buffer_data = 22; int32 api = 23; diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index bba880ec90..d3be0ea1bb 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -82,7 +82,6 @@ cc_test { "SurfaceFlinger_SetPowerModeInternalTest.cpp", "SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp", "SchedulerTest.cpp", - "SchedulerUtilsTest.cpp", "SetFrameRateTest.cpp", "RefreshRateConfigsTest.cpp", "RefreshRateSelectionTest.cpp", @@ -90,7 +89,6 @@ cc_test { "RegionSamplingTest.cpp", "TimeStatsTest.cpp", "FrameTracerTest.cpp", - "TimerTest.cpp", "TransactionApplicationTest.cpp", "TransactionFrameTracerTest.cpp", "TransactionProtoParserTest.cpp", @@ -179,11 +177,12 @@ cc_test { "server_configurable_flags", ], header_libs: [ + "android.hardware.graphics.composer3-command-buffer", "android.hardware.graphics.composer@2.1-command-buffer", "android.hardware.graphics.composer@2.2-command-buffer", "android.hardware.graphics.composer@2.3-command-buffer", "android.hardware.graphics.composer@2.4-command-buffer", - "android.hardware.graphics.composer3-command-buffer", + "libscheduler_test_headers", "libsurfaceflinger_headers", ], } diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index dee2358ab7..3716f59c26 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -30,6 +30,7 @@ #include <gui/IProducerListener.h> #include <gui/LayerMetadata.h> #include <log/log.h> +#include <renderengine/mock/FakeExternalTexture.h> #include <renderengine/mock/Framebuffer.h> #include <renderengine/mock/Image.h> #include <renderengine/mock/RenderEngine.h> @@ -233,15 +234,13 @@ void CompositionTest::captureScreenComposition() { CaptureArgs::UNSET_UID, visitor); }; - // TODO: Eliminate expensive/real allocation if possible. const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; - mCaptureScreenBuffer = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(renderArea->getReqWidth(), - renderArea->getReqHeight(), - HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, - "screenshot"), - *mRenderEngine, true); + mCaptureScreenBuffer = + std::make_shared<renderengine::mock::FakeExternalTexture>(renderArea->getReqWidth(), + renderArea->getReqHeight(), + HAL_PIXEL_FORMAT_RGBA_8888, 1, + usage); auto result = mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer, forSystem, regionSampling); diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp index a9ad249383..f613e43324 100644 --- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp +++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp @@ -37,12 +37,11 @@ using namespace testing; class MockVSyncDispatch : public scheduler::VSyncDispatch { public: - MOCK_METHOD2(registerCallback, - CallbackToken(std::function<void(nsecs_t, nsecs_t, nsecs_t)> const&, std::string)); - MOCK_METHOD1(unregisterCallback, void(CallbackToken)); - MOCK_METHOD2(schedule, scheduler::ScheduleResult(CallbackToken, ScheduleTiming)); - MOCK_METHOD1(cancel, scheduler::CancelResult(CallbackToken token)); - MOCK_CONST_METHOD1(dump, void(std::string&)); + MOCK_METHOD(CallbackToken, registerCallback, (Callback, std::string), (override)); + MOCK_METHOD(void, unregisterCallback, (CallbackToken), (override)); + MOCK_METHOD(scheduler::ScheduleResult, schedule, (CallbackToken, ScheduleTiming), (override)); + MOCK_METHOD(scheduler::CancelResult, cancel, (CallbackToken), (override)); + MOCK_METHOD(void, dump, (std::string&), (const, override)); MockVSyncDispatch() { ON_CALL(*this, registerCallback) diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp index bd4dc593ba..1dd7deaf8d 100644 --- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp @@ -56,12 +56,11 @@ public: }; struct MockVSyncDispatch : scheduler::VSyncDispatch { - MOCK_METHOD2(registerCallback, - CallbackToken(const std::function<void(nsecs_t, nsecs_t, nsecs_t)>&, std::string)); - MOCK_METHOD1(unregisterCallback, void(CallbackToken)); - MOCK_METHOD2(schedule, scheduler::ScheduleResult(CallbackToken, ScheduleTiming)); - MOCK_METHOD1(cancel, scheduler::CancelResult(CallbackToken token)); - MOCK_CONST_METHOD1(dump, void(std::string&)); + MOCK_METHOD(CallbackToken, registerCallback, (Callback, std::string), (override)); + MOCK_METHOD(void, unregisterCallback, (CallbackToken), (override)); + MOCK_METHOD(scheduler::ScheduleResult, schedule, (CallbackToken, ScheduleTiming), (override)); + MOCK_METHOD(scheduler::CancelResult, cancel, (CallbackToken token), (override)); + MOCK_METHOD(void, dump, (std::string&), (const, override)); }; struct MockTokenManager : frametimeline::TokenManager { diff --git a/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp deleted file mode 100644 index 5f6a7150d6..0000000000 --- a/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// 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" - -#include <gmock/gmock.h> -#include <gtest/gtest.h> - -#include <array> - -#include "Scheduler/SchedulerUtils.h" - -namespace android { -namespace scheduler { - -class SchedulerUtilsTest : public testing::Test { -public: - SchedulerUtilsTest() = default; - ~SchedulerUtilsTest() override = default; -}; - -namespace { -TEST_F(SchedulerUtilsTest, calculate_mean) { - std::array<int64_t, 30> testArray{}; - // Calling the function on empty array returns 0. - EXPECT_EQ(0, calculate_mean(testArray)); - - testArray[0] = 33; - EXPECT_EQ(1, calculate_mean(testArray)); - testArray[1] = 33; - testArray[2] = 33; - EXPECT_EQ(3, calculate_mean(testArray)); - testArray[3] = 42; - EXPECT_EQ(4, calculate_mean(testArray)); - testArray[4] = 33; - EXPECT_EQ(5, calculate_mean(testArray)); - testArray[5] = 42; - EXPECT_EQ(7, calculate_mean(testArray)); - for (int i = 6; i < 30; i++) { - testArray[i] = 33; - } - EXPECT_EQ(33, calculate_mean(testArray)); -} - -TEST_F(SchedulerUtilsTest, calculate_median) { - std::vector<int64_t> testVector; - // Calling the function on empty vector returns 0. - EXPECT_EQ(0, calculate_median(&testVector)); - - testVector.push_back(33); - EXPECT_EQ(33, calculate_median(&testVector)); - testVector.push_back(33); - testVector.push_back(33); - EXPECT_EQ(33, calculate_median(&testVector)); - testVector.push_back(42); - EXPECT_EQ(33, calculate_median(&testVector)); - testVector.push_back(33); - EXPECT_EQ(33, calculate_median(&testVector)); - testVector.push_back(42); - EXPECT_EQ(33, calculate_median(&testVector)); - testVector.push_back(42); - EXPECT_EQ(33, calculate_median(&testVector)); - testVector.push_back(42); - EXPECT_EQ(42, calculate_median(&testVector)); - testVector.push_back(60); - EXPECT_EQ(42, calculate_median(&testVector)); - testVector.push_back(60); - EXPECT_EQ(42, calculate_median(&testVector)); - testVector.push_back(33); - EXPECT_EQ(42, calculate_median(&testVector)); - testVector.push_back(33); - EXPECT_EQ(42, calculate_median(&testVector)); - testVector.push_back(33); - EXPECT_EQ(33, calculate_median(&testVector)); -} - -TEST_F(SchedulerUtilsTest, calculate_mode) { - std::vector<int64_t> testVector; - // Calling the function on empty vector returns 0. - EXPECT_EQ(0, calculate_mode(testVector)); - - testVector.push_back(33); - EXPECT_EQ(33, calculate_mode(testVector)); - testVector.push_back(33); - testVector.push_back(33); - EXPECT_EQ(33, calculate_mode(testVector)); - testVector.push_back(42); - EXPECT_EQ(33, calculate_mode(testVector)); - testVector.push_back(33); - EXPECT_EQ(33, calculate_mode(testVector)); - testVector.push_back(42); - EXPECT_EQ(33, calculate_mode(testVector)); - testVector.push_back(42); - EXPECT_EQ(33, calculate_mode(testVector)); - testVector.push_back(42); - EXPECT_EQ(33, calculate_mode(testVector)); - testVector.push_back(60); - EXPECT_EQ(33, calculate_mode(testVector)); - testVector.push_back(60); - EXPECT_EQ(33, calculate_mode(testVector)); - testVector.push_back(33); - // 5 occurences of 33. - EXPECT_EQ(33, calculate_mode(testVector)); - testVector.push_back(42); - // 5 occurences of 33, 5 occurences of 42. We choose the first one. - EXPECT_EQ(33, calculate_mode(testVector)); - testVector.push_back(42); - // 5 occurences of 33, 6 occurences of 42. - EXPECT_EQ(42, calculate_mode(testVector)); - testVector.push_back(42); - // 5 occurences of 33, 7 occurences of 42. - EXPECT_EQ(42, calculate_mode(testVector)); -} - -} // 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/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp index deeb785bb9..5364630400 100644 --- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp @@ -22,6 +22,7 @@ #include <gui/SurfaceComposerClient.h> #include <log/log.h> #include <renderengine/ExternalTexture.h> +#include <renderengine/mock/FakeExternalTexture.h> #include <renderengine/mock/RenderEngine.h> #include <utils/String8.h> @@ -101,9 +102,8 @@ public: sp<BufferStateLayer> layer = createBufferStateLayer(); sp<Fence> fence(new Fence()); - const auto buffer = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0); int32_t layerId = layer->getSequence(); - uint64_t bufferId = buffer->getId(); + uint64_t bufferId = 42; uint64_t frameNumber = 5; nsecs_t dequeueTime = 10; nsecs_t postTime = 20; @@ -115,13 +115,16 @@ public: traceTimestamp(layerId, bufferId, frameNumber, postTime, FrameTracer::FrameEvent::QUEUE, /*duration*/ 0)); BufferData bufferData; - bufferData.buffer = buffer; bufferData.acquireFence = fence; bufferData.frameNumber = frameNumber; bufferData.flags |= BufferData::BufferDataChange::fenceChanged; bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged; - layer->setBuffer(bufferData, postTime, /*desiredPresentTime*/ 30, false, dequeueTime, - FrameTimelineInfo{}); + std::shared_ptr<renderengine::ExternalTexture> externalTexture = std::make_shared< + renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, bufferId, + HAL_PIXEL_FORMAT_RGBA_8888, + 0ULL /*usage*/); + layer->setBuffer(externalTexture, bufferData, postTime, /*desiredPresentTime*/ 30, false, + dequeueTime, FrameTimelineInfo{}); commitTransaction(layer.get()); bool computeVisisbleRegions; diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp index 704340deac..5bb4c92a8e 100644 --- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp @@ -22,6 +22,7 @@ #include <gui/SurfaceComposerClient.h> #include <log/log.h> #include <renderengine/ExternalTexture.h> +#include <renderengine/mock/FakeExternalTexture.h> #include <renderengine/mock/RenderEngine.h> #include <utils/String8.h> @@ -114,14 +115,17 @@ public: sp<BufferStateLayer> layer = createBufferStateLayer(); sp<Fence> fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - const auto buffer = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0); BufferData bufferData; - bufferData.buffer = buffer; bufferData.acquireFence = fence; bufferData.frameNumber = 1; bufferData.flags |= BufferData::BufferDataChange::fenceChanged; bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged; - layer->setBuffer(bufferData, 10, 20, false, std::nullopt, + std::shared_ptr<renderengine::ExternalTexture> externalTexture = std::make_shared< + renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, + 1ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0ULL /*usage*/); + layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}); acquireFence->signalForTest(12); @@ -145,14 +149,17 @@ public: sp<Fence> fence1(new Fence()); auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); - const auto buffer1 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0); BufferData bufferData; - bufferData.buffer = buffer1; bufferData.acquireFence = fence1; bufferData.frameNumber = 1; bufferData.flags |= BufferData::BufferDataChange::fenceChanged; bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged; - layer->setBuffer(bufferData, 10, 20, false, std::nullopt, + std::shared_ptr<renderengine::ExternalTexture> externalTexture1 = std::make_shared< + renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, + 1ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0ULL /*usage*/); + layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); @@ -160,14 +167,17 @@ public: sp<Fence> fence2(new Fence()); auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); - const auto buffer2 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0); nsecs_t start = systemTime(); - bufferData.buffer = buffer2; bufferData.acquireFence = fence2; bufferData.frameNumber = 1; bufferData.flags |= BufferData::BufferDataChange::fenceChanged; bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged; - layer->setBuffer(bufferData, 10, 20, false, std::nullopt, + std::shared_ptr<renderengine::ExternalTexture> externalTexture2 = std::make_shared< + renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, + 2ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0ULL /*usage*/); + layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}); nsecs_t end = systemTime(); acquireFence2->signalForTest(12); @@ -203,14 +213,17 @@ public: sp<Fence> fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - const auto buffer = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0); BufferData bufferData; - bufferData.buffer = buffer; bufferData.acquireFence = fence; bufferData.frameNumber = 1; bufferData.flags |= BufferData::BufferDataChange::fenceChanged; bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged; - layer->setBuffer(bufferData, 10, 20, false, std::nullopt, + std::shared_ptr<renderengine::ExternalTexture> externalTexture = std::make_shared< + renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, + 1ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0ULL /*usage*/); + layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}); acquireFence->signalForTest(12); @@ -234,14 +247,17 @@ public: sp<BufferStateLayer> layer = createBufferStateLayer(); sp<Fence> fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - const auto buffer = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0); BufferData bufferData; - bufferData.buffer = buffer; bufferData.acquireFence = fence; bufferData.frameNumber = 1; bufferData.flags |= BufferData::BufferDataChange::fenceChanged; bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged; - layer->setBuffer(bufferData, 10, 20, false, std::nullopt, + std::shared_ptr<renderengine::ExternalTexture> externalTexture = std::make_shared< + renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, + 1ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0ULL /*usage*/); + layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); @@ -269,14 +285,17 @@ public: sp<Fence> fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - const auto buffer = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0); BufferData bufferData; - bufferData.buffer = buffer; bufferData.acquireFence = fence; bufferData.frameNumber = 1; bufferData.flags |= BufferData::BufferDataChange::fenceChanged; bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged; - layer->setBuffer(bufferData, 10, 20, false, std::nullopt, + std::shared_ptr<renderengine::ExternalTexture> externalTexture = std::make_shared< + renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, + 1ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0ULL /*usage*/); + layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, {/*vsyncId*/ 3, /*inputEventId*/ 0}); EXPECT_EQ(2u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); @@ -310,27 +329,33 @@ public: sp<Fence> fence1(new Fence()); auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); - const auto buffer1 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0); BufferData bufferData; - bufferData.buffer = buffer1; bufferData.acquireFence = fence1; bufferData.frameNumber = 1; bufferData.flags |= BufferData::BufferDataChange::fenceChanged; bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged; - layer->setBuffer(bufferData, 10, 20, false, std::nullopt, + std::shared_ptr<renderengine::ExternalTexture> externalTexture1 = std::make_shared< + renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, + 1ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0ULL /*usage*/); + layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX; sp<Fence> fence2(new Fence()); auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); - const auto buffer2 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0); - bufferData.buffer = buffer2; bufferData.acquireFence = fence2; bufferData.frameNumber = 1; bufferData.flags |= BufferData::BufferDataChange::fenceChanged; bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged; - layer->setBuffer(bufferData, 10, 20, false, std::nullopt, + std::shared_ptr<renderengine::ExternalTexture> externalTexture2 = std::make_shared< + renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, + 1ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0ULL /*usage*/); + layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}); acquireFence2->signalForTest(12); @@ -356,14 +381,17 @@ public: sp<Fence> fence1(new Fence()); auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); - const auto buffer1 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0); BufferData bufferData; - bufferData.buffer = buffer1; bufferData.acquireFence = fence1; bufferData.frameNumber = 1; bufferData.flags |= BufferData::BufferDataChange::fenceChanged; bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged; - layer->setBuffer(bufferData, 10, 20, false, std::nullopt, + std::shared_ptr<renderengine::ExternalTexture> externalTexture1 = std::make_shared< + renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, + 1ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0ULL /*usage*/); + layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); @@ -371,14 +399,17 @@ public: sp<Fence> fence2(new Fence()); auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); - const auto buffer2 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0); auto dropStartTime1 = systemTime(); - bufferData.buffer = buffer2; bufferData.acquireFence = fence2; bufferData.frameNumber = 1; bufferData.flags |= BufferData::BufferDataChange::fenceChanged; bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged; - layer->setBuffer(bufferData, 10, 20, false, std::nullopt, + std::shared_ptr<renderengine::ExternalTexture> externalTexture2 = std::make_shared< + renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, + 1ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0ULL /*usage*/); + layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, {/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0}); auto dropEndTime1 = systemTime(); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); @@ -387,14 +418,17 @@ public: sp<Fence> fence3(new Fence()); auto acquireFence3 = fenceFactory.createFenceTimeForTest(fence3); - const auto buffer3 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0); auto dropStartTime2 = systemTime(); - bufferData.buffer = buffer3; bufferData.acquireFence = fence3; bufferData.frameNumber = 1; bufferData.flags |= BufferData::BufferDataChange::fenceChanged; bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged; - layer->setBuffer(bufferData, 10, 20, false, std::nullopt, + std::shared_ptr<renderengine::ExternalTexture> externalTexture3 = std::make_shared< + renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, + 1ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0ULL /*usage*/); + layer->setBuffer(externalTexture3, bufferData, 10, 20, false, std::nullopt, {/*vsyncId*/ 2, /*inputEventId*/ 0}); auto dropEndTime2 = systemTime(); acquireFence3->signalForTest(12); @@ -432,14 +466,17 @@ public: std::vector<std::shared_ptr<frametimeline::SurfaceFrame>> bufferlessSurfaceFrames; for (int i = 0; i < 10; i += 2) { sp<Fence> fence(new Fence()); - const auto buffer = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0); BufferData bufferData; - bufferData.buffer = buffer; bufferData.acquireFence = fence; bufferData.frameNumber = 1; bufferData.flags |= BufferData::BufferDataChange::fenceChanged; bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged; - layer->setBuffer(bufferData, 10, 20, false, std::nullopt, + std::shared_ptr<renderengine::ExternalTexture> externalTexture = std::make_shared< + renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, + 1ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0ULL /*usage*/); + layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}); layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 2, /*inputEventId*/ 0}, diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp index 43b09fd33d..5ac581288e 100644 --- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp @@ -29,79 +29,32 @@ namespace android { class TransactionTracingTest : public testing::Test { protected: static constexpr size_t SMALL_BUFFER_SIZE = 1024; - std::unique_ptr<android::TransactionTracing> mTracing; - void SetUp() override { mTracing = std::make_unique<android::TransactionTracing>(); } + TransactionTracing mTracing; - void TearDown() override { - mTracing->disable(); - mTracing.reset(); - } - - auto getCommittedTransactions() { - std::scoped_lock<std::mutex> lock(mTracing->mMainThreadLock); - return mTracing->mCommittedTransactions; - } - - auto getQueuedTransactions() { - std::scoped_lock<std::mutex> lock(mTracing->mTraceLock); - return mTracing->mQueuedTransactions; - } - - auto getUsedBufferSize() { - std::scoped_lock<std::mutex> lock(mTracing->mTraceLock); - return mTracing->mBuffer->used(); - } - - auto flush(int64_t vsyncId) { return mTracing->flush(vsyncId); } + void flush(int64_t vsyncId) { mTracing.flush(vsyncId); } + proto::TransactionTraceFile writeToProto() { return mTracing.writeToProto(); } - auto bufferFront() { - std::scoped_lock<std::mutex> lock(mTracing->mTraceLock); + proto::TransactionTraceEntry bufferFront() { + std::scoped_lock<std::mutex> lock(mTracing.mTraceLock); proto::TransactionTraceEntry entry; - entry.ParseFromString(mTracing->mBuffer->front()); + entry.ParseFromString(mTracing.mBuffer.front()); return entry; } - bool threadIsJoinable() { - std::scoped_lock lock(mTracing->mMainThreadLock); - return mTracing->mThread.joinable(); - } - - proto::TransactionTraceFile writeToProto() { return mTracing->writeToProto(); } - - auto getCreatedLayers() { - std::scoped_lock<std::mutex> lock(mTracing->mTraceLock); - return mTracing->mCreatedLayers; - } - - auto getStartingStates() { - std::scoped_lock<std::mutex> lock(mTracing->mTraceLock); - return mTracing->mStartingStates; - } - void queueAndCommitTransaction(int64_t vsyncId) { TransactionState transaction; transaction.id = static_cast<uint64_t>(vsyncId * 3); transaction.originUid = 1; transaction.originPid = 2; - mTracing->addQueuedTransaction(transaction); + mTracing.addQueuedTransaction(transaction); std::vector<TransactionState> transactions; transactions.emplace_back(transaction); - mTracing->addCommittedTransactions(transactions, vsyncId); + mTracing.addCommittedTransactions(transactions, vsyncId); flush(vsyncId); } - // Test that we clean up the tracing thread and free any memory allocated. - void verifyDisabledTracingState() { - EXPECT_FALSE(mTracing->isEnabled()); - EXPECT_FALSE(threadIsJoinable()); - EXPECT_EQ(getCommittedTransactions().size(), 0u); - EXPECT_EQ(getQueuedTransactions().size(), 0u); - EXPECT_EQ(getUsedBufferSize(), 0u); - EXPECT_EQ(getStartingStates().size(), 0u); - } - void verifyEntry(const proto::TransactionTraceEntry& actualProto, - const std::vector<TransactionState> expectedTransactions, + const std::vector<TransactionState>& expectedTransactions, int64_t expectedVsyncId) { EXPECT_EQ(actualProto.vsync_id(), expectedVsyncId); EXPECT_EQ(actualProto.transactions().size(), @@ -113,16 +66,7 @@ protected: } }; -TEST_F(TransactionTracingTest, enable) { - EXPECT_FALSE(mTracing->isEnabled()); - mTracing->enable(); - EXPECT_TRUE(mTracing->isEnabled()); - mTracing->disable(); - verifyDisabledTracingState(); -} - TEST_F(TransactionTracingTest, addTransactions) { - mTracing->enable(); std::vector<TransactionState> transactions; transactions.reserve(100); for (uint64_t i = 0; i < 100; i++) { @@ -130,7 +74,7 @@ TEST_F(TransactionTracingTest, addTransactions) { transaction.id = i; transaction.originPid = static_cast<int32_t>(i); transactions.emplace_back(transaction); - mTracing->addQueuedTransaction(transaction); + mTracing.addQueuedTransaction(transaction); } // Split incoming transactions into two and commit them in reverse order to test out of order @@ -138,12 +82,12 @@ TEST_F(TransactionTracingTest, addTransactions) { std::vector<TransactionState> firstTransactionSet = std::vector<TransactionState>(transactions.begin() + 50, transactions.end()); int64_t firstTransactionSetVsyncId = 42; - mTracing->addCommittedTransactions(firstTransactionSet, firstTransactionSetVsyncId); + mTracing.addCommittedTransactions(firstTransactionSet, firstTransactionSetVsyncId); int64_t secondTransactionSetVsyncId = 43; std::vector<TransactionState> secondTransactionSet = std::vector<TransactionState>(transactions.begin(), transactions.begin() + 50); - mTracing->addCommittedTransactions(secondTransactionSet, secondTransactionSetVsyncId); + mTracing.addCommittedTransactions(secondTransactionSet, secondTransactionSetVsyncId); flush(secondTransactionSetVsyncId); proto::TransactionTraceFile proto = writeToProto(); @@ -151,24 +95,19 @@ TEST_F(TransactionTracingTest, addTransactions) { // skip starting entry verifyEntry(proto.entry(1), firstTransactionSet, firstTransactionSetVsyncId); verifyEntry(proto.entry(2), secondTransactionSet, secondTransactionSetVsyncId); - - mTracing->disable(); - verifyDisabledTracingState(); } class TransactionTracingLayerHandlingTest : public TransactionTracingTest { protected: void SetUp() override { - TransactionTracingTest::SetUp(); - mTracing->enable(); // add layers - mTracing->setBufferSize(SMALL_BUFFER_SIZE); + mTracing.setBufferSize(SMALL_BUFFER_SIZE); const sp<IBinder> fakeLayerHandle = new BBinder(); - mTracing->onLayerAdded(fakeLayerHandle->localBinder(), mParentLayerId, "parent", - 123 /* flags */, -1 /* parentId */); + mTracing.onLayerAdded(fakeLayerHandle->localBinder(), mParentLayerId, "parent", + 123 /* flags */, -1 /* parentId */); const sp<IBinder> fakeChildLayerHandle = new BBinder(); - mTracing->onLayerAdded(fakeChildLayerHandle->localBinder(), mChildLayerId, "child", - 456 /* flags */, mParentLayerId); + mTracing.onLayerAdded(fakeChildLayerHandle->localBinder(), mChildLayerId, "child", + 456 /* flags */, mParentLayerId); // add some layer transaction { @@ -184,12 +123,12 @@ protected: childState.state.what = layer_state_t::eLayerChanged; childState.state.z = 43; transaction.states.add(childState); - mTracing->addQueuedTransaction(transaction); + mTracing.addQueuedTransaction(transaction); std::vector<TransactionState> transactions; transactions.emplace_back(transaction); VSYNC_ID_FIRST_LAYER_CHANGE = ++mVsyncId; - mTracing->addCommittedTransactions(transactions, VSYNC_ID_FIRST_LAYER_CHANGE); + mTracing.addCommittedTransactions(transactions, VSYNC_ID_FIRST_LAYER_CHANGE); flush(VSYNC_ID_FIRST_LAYER_CHANGE); } @@ -204,31 +143,25 @@ protected: layerState.state.z = 41; layerState.state.x = 22; transaction.states.add(layerState); - mTracing->addQueuedTransaction(transaction); + mTracing.addQueuedTransaction(transaction); std::vector<TransactionState> transactions; transactions.emplace_back(transaction); VSYNC_ID_SECOND_LAYER_CHANGE = ++mVsyncId; - mTracing->addCommittedTransactions(transactions, VSYNC_ID_SECOND_LAYER_CHANGE); + mTracing.addCommittedTransactions(transactions, VSYNC_ID_SECOND_LAYER_CHANGE); flush(VSYNC_ID_SECOND_LAYER_CHANGE); } // remove child layer - mTracing->onLayerRemoved(2); + mTracing.onLayerRemoved(2); VSYNC_ID_CHILD_LAYER_REMOVED = ++mVsyncId; queueAndCommitTransaction(VSYNC_ID_CHILD_LAYER_REMOVED); // remove layer - mTracing->onLayerRemoved(1); + mTracing.onLayerRemoved(1); queueAndCommitTransaction(++mVsyncId); } - void TearDown() override { - mTracing->disable(); - verifyDisabledTracingState(); - TransactionTracingTest::TearDown(); - } - int mParentLayerId = 1; int mChildLayerId = 2; int64_t mVsyncId = 0; @@ -298,16 +231,14 @@ TEST_F(TransactionTracingLayerHandlingTest, startingStateSurvivesBufferFlush) { class TransactionTracingMirrorLayerTest : public TransactionTracingTest { protected: void SetUp() override { - TransactionTracingTest::SetUp(); - mTracing->enable(); // add layers - mTracing->setBufferSize(SMALL_BUFFER_SIZE); + mTracing.setBufferSize(SMALL_BUFFER_SIZE); const sp<IBinder> fakeLayerHandle = new BBinder(); - mTracing->onLayerAdded(fakeLayerHandle->localBinder(), mLayerId, "Test Layer", - 123 /* flags */, -1 /* parentId */); + mTracing.onLayerAdded(fakeLayerHandle->localBinder(), mLayerId, "Test Layer", + 123 /* flags */, -1 /* parentId */); const sp<IBinder> fakeMirrorLayerHandle = new BBinder(); - mTracing->onMirrorLayerAdded(fakeMirrorLayerHandle->localBinder(), mMirrorLayerId, "Mirror", - mLayerId); + mTracing.onMirrorLayerAdded(fakeMirrorLayerHandle->localBinder(), mMirrorLayerId, "Mirror", + mLayerId); // add some layer transaction { @@ -323,21 +254,15 @@ protected: mirrorState.state.what = layer_state_t::eLayerChanged; mirrorState.state.z = 43; transaction.states.add(mirrorState); - mTracing->addQueuedTransaction(transaction); + mTracing.addQueuedTransaction(transaction); std::vector<TransactionState> transactions; transactions.emplace_back(transaction); - mTracing->addCommittedTransactions(transactions, ++mVsyncId); + mTracing.addCommittedTransactions(transactions, ++mVsyncId); flush(mVsyncId); } } - void TearDown() override { - mTracing->disable(); - verifyDisabledTracingState(); - TransactionTracingTest::TearDown(); - } - int mLayerId = 5; int mMirrorLayerId = 55; int64_t mVsyncId = 0; diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp index 42b19933b4..2da266bd33 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp @@ -14,14 +14,15 @@ * limitations under the License. */ -#include "Scheduler/TimeKeeper.h" -#include "Scheduler/Timer.h" -#include "Scheduler/VSyncDispatchTimerQueue.h" -#include "Scheduler/VSyncTracker.h" +#include <thread> #include <gmock/gmock.h> #include <gtest/gtest.h> -#include <thread> + +#include <scheduler/Timer.h> + +#include "Scheduler/VSyncDispatchTimerQueue.h" +#include "Scheduler/VSyncTracker.h" using namespace testing; using namespace std::literals; diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp index ddc02bfbe6..b7f968dc17 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp @@ -23,16 +23,19 @@ #define LOG_TAG "LibSurfaceFlingerUnittests" #define LOG_NDEBUG 0 -#include "Scheduler/TimeKeeper.h" -#include "Scheduler/VSyncDispatchTimerQueue.h" -#include "Scheduler/VSyncTracker.h" +#include <thread> #include <gmock/gmock.h> #include <gtest/gtest.h> -#include <thread> + +#include <scheduler/TimeKeeper.h> + +#include "Scheduler/VSyncDispatchTimerQueue.h" +#include "Scheduler/VSyncTracker.h" using namespace testing; using namespace std::literals; + namespace android::scheduler { class MockVSyncTracker : public VSyncTracker { @@ -71,10 +74,10 @@ public: ON_CALL(*this, now()).WillByDefault(Invoke(this, &ControllableClock::fakeTime)); } - MOCK_CONST_METHOD0(now, nsecs_t()); - MOCK_METHOD2(alarmAt, void(std::function<void()> const&, nsecs_t time)); - MOCK_METHOD0(alarmCancel, void()); - MOCK_CONST_METHOD1(dump, void(std::string&)); + MOCK_METHOD(nsecs_t, now, (), (const)); + MOCK_METHOD(void, alarmAt, (std::function<void()>, nsecs_t), (override)); + MOCK_METHOD(void, alarmCancel, (), (override)); + MOCK_METHOD(void, dump, (std::string&), (const, override)); void alarmAtDefaultBehavior(std::function<void()> const& callback, nsecs_t time) { mCallback = callback; @@ -196,11 +199,14 @@ protected: class TimeKeeperWrapper : public TimeKeeper { public: TimeKeeperWrapper(TimeKeeper& control) : mControllableClock(control) {} - void alarmAt(std::function<void()> const& callback, nsecs_t time) final { - mControllableClock.alarmAt(callback, time); + + nsecs_t now() const final { return mControllableClock.now(); } + + void alarmAt(std::function<void()> callback, nsecs_t time) final { + mControllableClock.alarmAt(std::move(callback), time); } + void alarmCancel() final { mControllableClock.alarmCancel(); } - nsecs_t now() const final { return mControllableClock.now(); } void dump(std::string&) const final {} private: diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp index 5826a9b6cf..4eb90558ab 100644 --- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp @@ -22,19 +22,22 @@ #define LOG_TAG "LibSurfaceFlingerUnittests" #define LOG_NDEBUG 0 -#include "Scheduler/TimeKeeper.h" -#include "Scheduler/VSyncDispatch.h" -#include "Scheduler/VSyncReactor.h" -#include "Scheduler/VSyncTracker.h" +#include <array> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <ui/Fence.h> #include <ui/FenceTime.h> -#include <array> + +#include <scheduler/TimeKeeper.h> + +#include "Scheduler/VSyncDispatch.h" +#include "Scheduler/VSyncReactor.h" +#include "Scheduler/VSyncTracker.h" using namespace testing; using namespace std::literals; + namespace android::scheduler { class MockVSyncTracker : public VSyncTracker { @@ -65,14 +68,12 @@ private: std::shared_ptr<Clock> const mClock; }; -class MockVSyncDispatch : public VSyncDispatch { -public: - MOCK_METHOD2(registerCallback, - CallbackToken(std::function<void(nsecs_t, nsecs_t, nsecs_t)> const&, std::string)); - MOCK_METHOD1(unregisterCallback, void(CallbackToken)); - MOCK_METHOD2(schedule, ScheduleResult(CallbackToken, ScheduleTiming)); - MOCK_METHOD1(cancel, CancelResult(CallbackToken token)); - MOCK_CONST_METHOD1(dump, void(std::string&)); +struct MockVSyncDispatch : VSyncDispatch { + MOCK_METHOD(CallbackToken, registerCallback, (Callback, std::string), (override)); + MOCK_METHOD(void, unregisterCallback, (CallbackToken), (override)); + MOCK_METHOD(ScheduleResult, schedule, (CallbackToken, ScheduleTiming), (override)); + MOCK_METHOD(CancelResult, cancel, (CallbackToken), (override)); + MOCK_METHOD(void, dump, (std::string&), (const, override)); }; std::shared_ptr<android::FenceTime> generateInvalidFence() { @@ -497,4 +498,4 @@ TEST_F(VSyncReactorTest, periodIsMeasuredIfIgnoringComposer) { } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file +#pragma clang diagnostic pop // ignored "-Wextra" |