|  | /* | 
|  | * Copyright (C) 2019 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  | #pragma once | 
|  |  | 
|  | #include <gtest/gtest.h> | 
|  | #include <gui/SurfaceComposerClient.h> | 
|  | #include <gui/SurfaceControl.h> | 
|  | #include <ui/Fence.h> | 
|  | #include <utils/Timers.h> | 
|  | #include <thread> | 
|  |  | 
|  | namespace android { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | struct CallbackData { | 
|  | CallbackData() = default; | 
|  | CallbackData(nsecs_t time, const sp<Fence>& fence, | 
|  | const std::vector<SurfaceControlStats>& stats) | 
|  | : latchTime(time), presentFence(fence), surfaceControlStats(stats) {} | 
|  |  | 
|  | nsecs_t latchTime; | 
|  | sp<Fence> presentFence; | 
|  | std::vector<SurfaceControlStats> surfaceControlStats; | 
|  | }; | 
|  |  | 
|  | class ExpectedResult { | 
|  | public: | 
|  | enum Transaction { | 
|  | NOT_PRESENTED = 0, | 
|  | PRESENTED, | 
|  | }; | 
|  |  | 
|  | enum Buffer { | 
|  | NOT_ACQUIRED = 0, | 
|  | ACQUIRED, | 
|  | }; | 
|  |  | 
|  | enum PreviousBuffer { | 
|  | NOT_RELEASED = 0, | 
|  | RELEASED, | 
|  | UNKNOWN, | 
|  | }; | 
|  |  | 
|  | void reset() { | 
|  | mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED; | 
|  | mExpectedSurfaceResults.clear(); | 
|  | } | 
|  |  | 
|  | void addSurface(ExpectedResult::Transaction transactionResult, const sp<SurfaceControl>& layer, | 
|  | ExpectedResult::Buffer bufferResult = ACQUIRED, | 
|  | ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) { | 
|  | mTransactionResult = transactionResult; | 
|  | mExpectedSurfaceResults.emplace(std::piecewise_construct, std::forward_as_tuple(layer), | 
|  | std::forward_as_tuple(bufferResult, previousBufferResult)); | 
|  | } | 
|  |  | 
|  | void addSurfaces(ExpectedResult::Transaction transactionResult, | 
|  | const std::vector<sp<SurfaceControl>>& layers, | 
|  | ExpectedResult::Buffer bufferResult = ACQUIRED, | 
|  | ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) { | 
|  | for (const auto& layer : layers) { | 
|  | addSurface(transactionResult, layer, bufferResult, previousBufferResult); | 
|  | } | 
|  | } | 
|  |  | 
|  | void addExpectedPresentTime(nsecs_t expectedPresentTime) { | 
|  | mExpectedPresentTime = expectedPresentTime; | 
|  | } | 
|  |  | 
|  | void addExpectedPresentTimeForVsyncId(nsecs_t expectedPresentTime) { | 
|  | mExpectedPresentTimeForVsyncId = expectedPresentTime; | 
|  | } | 
|  |  | 
|  | void verifyCallbackData(const CallbackData& callbackData) const { | 
|  | const auto& [latchTime, presentFence, surfaceControlStats] = callbackData; | 
|  | if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) { | 
|  | ASSERT_GE(latchTime, 0) << "bad latch time"; | 
|  | ASSERT_NE(presentFence, nullptr); | 
|  | if (mExpectedPresentTime >= 0) { | 
|  | ASSERT_EQ(presentFence->wait(3000), NO_ERROR); | 
|  | ASSERT_GE(presentFence->getSignalTime(), mExpectedPresentTime - nsecs_t(5 * 1e6)); | 
|  | // if the panel is running at 30 hz, at the worst case, our expected time just | 
|  | // misses vsync and we have to wait another 33.3ms | 
|  | ASSERT_LE(presentFence->getSignalTime(), | 
|  | mExpectedPresentTime + nsecs_t(66.666666 * 1e6)); | 
|  | } else if (mExpectedPresentTimeForVsyncId >= 0) { | 
|  | ASSERT_EQ(presentFence->wait(3000), NO_ERROR); | 
|  | // We give 4ms for prediction error | 
|  | ASSERT_GE(presentFence->getSignalTime(), | 
|  | mExpectedPresentTimeForVsyncId - 4'000'000); | 
|  | } | 
|  | } else { | 
|  | ASSERT_EQ(presentFence, nullptr) << "transaction shouldn't have been presented"; | 
|  | ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched"; | 
|  | } | 
|  |  | 
|  | ASSERT_EQ(surfaceControlStats.size(), mExpectedSurfaceResults.size()) | 
|  | << "wrong number of surfaces"; | 
|  |  | 
|  | for (const auto& stats : surfaceControlStats) { | 
|  | ASSERT_NE(stats.surfaceControl, nullptr) << "returned null surface control"; | 
|  |  | 
|  | const auto& expectedSurfaceResult = mExpectedSurfaceResults.find(stats.surfaceControl); | 
|  | ASSERT_NE(expectedSurfaceResult, mExpectedSurfaceResults.end()) | 
|  | << "unexpected surface control"; | 
|  | expectedSurfaceResult->second.verifySurfaceControlStats(stats, latchTime); | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | class ExpectedSurfaceResult { | 
|  | public: | 
|  | ExpectedSurfaceResult(ExpectedResult::Buffer bufferResult, | 
|  | ExpectedResult::PreviousBuffer previousBufferResult) | 
|  | : mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {} | 
|  |  | 
|  | void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats, | 
|  | nsecs_t latchTime) const { | 
|  | const auto& | 
|  | [surfaceControl, latch, acquireTime, presentFence, previousReleaseFence, | 
|  | transformHint, | 
|  | frameEvents] = surfaceControlStats; | 
|  |  | 
|  | ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED) | 
|  | << "bad acquire time"; | 
|  | ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time"; | 
|  |  | 
|  | if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED) { | 
|  | ASSERT_NE(previousReleaseFence, nullptr) | 
|  | << "failed to set release prev buffer fence"; | 
|  | } else if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::NOT_RELEASED) { | 
|  | ASSERT_EQ(previousReleaseFence, nullptr) | 
|  | << "should not have set released prev buffer fence"; | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | ExpectedResult::Buffer mBufferResult; | 
|  | ExpectedResult::PreviousBuffer mPreviousBufferResult; | 
|  | }; | 
|  |  | 
|  | struct SCHash { | 
|  | std::size_t operator()(const sp<SurfaceControl>& sc) const { | 
|  | return std::hash<IBinder*>{}(sc->getHandle().get()); | 
|  | } | 
|  | }; | 
|  | ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED; | 
|  | nsecs_t mExpectedPresentTime = -1; | 
|  | nsecs_t mExpectedPresentTimeForVsyncId = -1; | 
|  | std::unordered_map<sp<SurfaceControl>, ExpectedSurfaceResult, SCHash> mExpectedSurfaceResults; | 
|  | }; | 
|  |  | 
|  | class CallbackHelper { | 
|  | public: | 
|  | static void function(void* callbackContext, nsecs_t latchTime, const sp<Fence>& presentFence, | 
|  | const std::vector<SurfaceControlStats>& stats) { | 
|  | if (!callbackContext) { | 
|  | ALOGE("failed to get callback context"); | 
|  | } | 
|  | CallbackHelper* helper = static_cast<CallbackHelper*>(callbackContext); | 
|  | std::lock_guard lock(helper->mMutex); | 
|  | helper->mCallbackDataQueue.emplace(latchTime, presentFence, stats); | 
|  | helper->mConditionVariable.notify_all(); | 
|  | } | 
|  |  | 
|  | void getCallbackData(CallbackData* outData) { | 
|  | std::unique_lock lock(mMutex); | 
|  |  | 
|  | if (mCallbackDataQueue.empty()) { | 
|  | ASSERT_NE(mConditionVariable.wait_for(lock, std::chrono::seconds(3)), | 
|  | std::cv_status::timeout) | 
|  | << "did not receive callback"; | 
|  | } | 
|  |  | 
|  | *outData = std::move(mCallbackDataQueue.front()); | 
|  | mCallbackDataQueue.pop(); | 
|  | } | 
|  |  | 
|  | void verifyFinalState() { | 
|  | // Wait to see if there are extra callbacks | 
|  | std::this_thread::sleep_for(500ms); | 
|  |  | 
|  | std::lock_guard lock(mMutex); | 
|  | EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received"; | 
|  | mCallbackDataQueue = {}; | 
|  | } | 
|  |  | 
|  | void* getContext() { return static_cast<void*>(this); } | 
|  |  | 
|  | std::mutex mMutex; | 
|  | std::condition_variable mConditionVariable; | 
|  | std::queue<CallbackData> mCallbackDataQueue; | 
|  | }; | 
|  | } | 
|  | } // namespace android |