/* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "Choreographer_test" #include #include #include #include #include #include #include #include namespace android { class ChoreographerTest : public ::testing::Test {}; struct VsyncCallback { std::atomic completePromise{false}; std::chrono::nanoseconds frameTime{0LL}; std::chrono::nanoseconds receivedCallbackTime{0LL}; void onVsyncCallback(const AChoreographerFrameCallbackData* callbackData) { frameTime = std::chrono::nanoseconds{ AChoreographerFrameCallbackData_getFrameTimeNanos(callbackData)}; receivedCallbackTime = std::chrono::nanoseconds{systemTime(SYSTEM_TIME_MONOTONIC)}; completePromise.store(true); } bool callbackReceived() { return completePromise.load(); } }; static void vsyncCallback(const AChoreographerFrameCallbackData* callbackData, void* data) { VsyncCallback* cb = static_cast(data); cb->onVsyncCallback(callbackData); } TEST_F(ChoreographerTest, InputCallbackBeforeAnimation) { sp looper = Looper::prepare(0); Choreographer* choreographer = Choreographer::getForThread(); VsyncCallback animationCb; VsyncCallback inputCb; choreographer->postFrameCallbackDelayed(nullptr, nullptr, vsyncCallback, &animationCb, 0, CALLBACK_ANIMATION); choreographer->postFrameCallbackDelayed(nullptr, nullptr, vsyncCallback, &inputCb, 0, CALLBACK_INPUT); nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); nsecs_t currTime; int pollResult; do { pollResult = looper->pollOnce(16); currTime = systemTime(SYSTEM_TIME_MONOTONIC); } while (!(inputCb.callbackReceived() && animationCb.callbackReceived()) && (pollResult != Looper::POLL_TIMEOUT && pollResult != Looper::POLL_ERROR) && (currTime - startTime < 3000)); ASSERT_TRUE(inputCb.callbackReceived()) << "did not receive input callback"; ASSERT_TRUE(animationCb.callbackReceived()) << "did not receive animation callback"; ASSERT_EQ(inputCb.frameTime, animationCb.frameTime) << android::base::StringPrintf("input and animation callback frame times don't match. " "inputFrameTime=%lld animationFrameTime=%lld", inputCb.frameTime.count(), animationCb.frameTime.count()); ASSERT_LT(inputCb.receivedCallbackTime, animationCb.receivedCallbackTime) << android::base::StringPrintf("input callback was not called first. " "inputCallbackTime=%lld animationCallbackTime=%lld", inputCb.frameTime.count(), animationCb.frameTime.count()); } } // namespace android