Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2023 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include <gmock/gmock.h> |
| 18 | #include <gtest/gtest.h> |
| 19 | #include <private/performance_hint_private.h> |
| 20 | #include <renderthread/HintSessionWrapper.h> |
| 21 | #include <utils/Log.h> |
| 22 | |
| 23 | #include <chrono> |
| 24 | |
| 25 | #include "Properties.h" |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 26 | #include "tests/common/TestUtils.h" |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 27 | |
| 28 | using namespace testing; |
| 29 | using namespace std::chrono_literals; |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 30 | using namespace android::uirenderer::renderthread; |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 31 | |
| 32 | APerformanceHintManager* managerPtr = reinterpret_cast<APerformanceHintManager*>(123); |
| 33 | APerformanceHintSession* sessionPtr = reinterpret_cast<APerformanceHintSession*>(456); |
| 34 | int uiThreadId = 1; |
| 35 | int renderThreadId = 2; |
| 36 | |
| 37 | namespace android::uirenderer::renderthread { |
| 38 | |
| 39 | class HintSessionWrapperTests : public testing::Test { |
| 40 | public: |
| 41 | void SetUp() override; |
| 42 | void TearDown() override; |
| 43 | |
| 44 | protected: |
| 45 | std::shared_ptr<HintSessionWrapper> mWrapper; |
| 46 | |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 47 | std::promise<int> blockDestroyCallUntil; |
| 48 | std::promise<int> waitForDestroyFinished; |
| 49 | |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 50 | class MockHintSessionBinding : public HintSessionWrapper::HintSessionBinding { |
| 51 | public: |
| 52 | void init() override; |
| 53 | |
| 54 | MOCK_METHOD(APerformanceHintManager*, fakeGetManager, ()); |
Matt Buckley | 27da134 | 2024-04-05 23:10:48 +0000 | [diff] [blame] | 55 | MOCK_METHOD(APerformanceHintSession*, fakeCreateSessionInternal, |
| 56 | (APerformanceHintManager*, const int32_t*, size_t, int64_t, SessionTag)); |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 57 | MOCK_METHOD(void, fakeCloseSession, (APerformanceHintSession*)); |
| 58 | MOCK_METHOD(void, fakeUpdateTargetWorkDuration, (APerformanceHintSession*, int64_t)); |
| 59 | MOCK_METHOD(void, fakeReportActualWorkDuration, (APerformanceHintSession*, int64_t)); |
| 60 | MOCK_METHOD(void, fakeSendHint, (APerformanceHintSession*, int32_t)); |
Igor Kraskevich | 2cec158 | 2024-03-13 11:23:40 +0000 | [diff] [blame] | 61 | MOCK_METHOD(int, fakeSetThreads, (APerformanceHintSession*, const std::vector<pid_t>&)); |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 62 | // Needs to be on the binding so it can be accessed from static methods |
| 63 | std::promise<int> allowCreationToFinish; |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 64 | }; |
| 65 | |
| 66 | // Must be static so it can have function pointers we can point to with static methods |
| 67 | static std::shared_ptr<MockHintSessionBinding> sMockBinding; |
| 68 | |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 69 | static void allowCreationToFinish() { sMockBinding->allowCreationToFinish.set_value(1); } |
| 70 | void allowDelayedDestructionToStart() { blockDestroyCallUntil.set_value(1); } |
| 71 | void waitForDelayedDestructionToFinish() { waitForDestroyFinished.get_future().wait(); } |
| 72 | |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 73 | // Must be static so we can point to them as normal fn pointers with HintSessionBinding |
| 74 | static APerformanceHintManager* stubGetManager() { return sMockBinding->fakeGetManager(); }; |
Matt Buckley | 27da134 | 2024-04-05 23:10:48 +0000 | [diff] [blame] | 75 | static APerformanceHintSession* stubCreateSessionInternal(APerformanceHintManager* manager, |
| 76 | const int32_t* ids, size_t idsSize, |
| 77 | int64_t initialTarget, |
| 78 | SessionTag tag) { |
| 79 | return sMockBinding->fakeCreateSessionInternal(manager, ids, idsSize, initialTarget, |
| 80 | SessionTag::HWUI); |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 81 | } |
Matt Buckley | 27da134 | 2024-04-05 23:10:48 +0000 | [diff] [blame] | 82 | static APerformanceHintSession* stubManagedCreateSessionInternal( |
| 83 | APerformanceHintManager* manager, const int32_t* ids, size_t idsSize, |
| 84 | int64_t initialTarget, SessionTag tag) { |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 85 | sMockBinding->allowCreationToFinish.get_future().wait(); |
Matt Buckley | 27da134 | 2024-04-05 23:10:48 +0000 | [diff] [blame] | 86 | return sMockBinding->fakeCreateSessionInternal(manager, ids, idsSize, initialTarget, |
| 87 | SessionTag::HWUI); |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 88 | } |
Matt Buckley | 27da134 | 2024-04-05 23:10:48 +0000 | [diff] [blame] | 89 | static APerformanceHintSession* stubSlowCreateSessionInternal(APerformanceHintManager* manager, |
| 90 | const int32_t* ids, |
| 91 | size_t idsSize, |
| 92 | int64_t initialTarget, |
| 93 | SessionTag tag) { |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 94 | std::this_thread::sleep_for(50ms); |
Matt Buckley | 27da134 | 2024-04-05 23:10:48 +0000 | [diff] [blame] | 95 | return sMockBinding->fakeCreateSessionInternal(manager, ids, idsSize, initialTarget, |
| 96 | SessionTag::HWUI); |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 97 | } |
| 98 | static void stubCloseSession(APerformanceHintSession* session) { |
| 99 | sMockBinding->fakeCloseSession(session); |
| 100 | }; |
| 101 | static void stubUpdateTargetWorkDuration(APerformanceHintSession* session, |
| 102 | int64_t workDuration) { |
| 103 | sMockBinding->fakeUpdateTargetWorkDuration(session, workDuration); |
| 104 | } |
| 105 | static void stubReportActualWorkDuration(APerformanceHintSession* session, |
| 106 | int64_t workDuration) { |
| 107 | sMockBinding->fakeReportActualWorkDuration(session, workDuration); |
| 108 | } |
| 109 | static void stubSendHint(APerformanceHintSession* session, int32_t hintId) { |
| 110 | sMockBinding->fakeSendHint(session, hintId); |
| 111 | }; |
Igor Kraskevich | 2cec158 | 2024-03-13 11:23:40 +0000 | [diff] [blame] | 112 | static int stubSetThreads(APerformanceHintSession* session, const pid_t* ids, size_t size) { |
| 113 | std::vector<pid_t> tids(ids, ids + size); |
| 114 | return sMockBinding->fakeSetThreads(session, tids); |
| 115 | } |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 116 | void waitForWrapperReady() { |
| 117 | if (mWrapper->mHintSessionFuture.has_value()) { |
| 118 | mWrapper->mHintSessionFuture->wait(); |
| 119 | } |
| 120 | } |
Igor Kraskevich | 2cec158 | 2024-03-13 11:23:40 +0000 | [diff] [blame] | 121 | void waitForSetThreadsReady() { |
| 122 | if (mWrapper->mSetThreadsFuture.has_value()) { |
| 123 | mWrapper->mSetThreadsFuture->wait(); |
| 124 | } |
| 125 | } |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 126 | void scheduleDelayedDestroyManaged() { |
| 127 | TestUtils::runOnRenderThread([&](renderthread::RenderThread& rt) { |
| 128 | // Guaranteed to be scheduled first, allows destruction to start |
| 129 | rt.queue().postDelayed(0_ms, [&] { blockDestroyCallUntil.get_future().wait(); }); |
| 130 | // Guaranteed to be scheduled second, destroys the session |
| 131 | mWrapper->delayedDestroy(rt, 1_ms, mWrapper); |
| 132 | // This is guaranteed to be queued after the destroy, signals that destruction is done |
| 133 | rt.queue().postDelayed(1_ms, [&] { waitForDestroyFinished.set_value(1); }); |
| 134 | }); |
| 135 | } |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 136 | }; |
| 137 | |
| 138 | std::shared_ptr<HintSessionWrapperTests::MockHintSessionBinding> |
| 139 | HintSessionWrapperTests::sMockBinding; |
| 140 | |
| 141 | void HintSessionWrapperTests::SetUp() { |
| 142 | // Pretend it's supported even if we're in an emulator |
| 143 | Properties::useHintManager = true; |
| 144 | sMockBinding = std::make_shared<NiceMock<MockHintSessionBinding>>(); |
| 145 | mWrapper = std::make_shared<HintSessionWrapper>(uiThreadId, renderThreadId); |
| 146 | mWrapper->mBinding = sMockBinding; |
| 147 | EXPECT_CALL(*sMockBinding, fakeGetManager).WillOnce(Return(managerPtr)); |
Matt Buckley | 27da134 | 2024-04-05 23:10:48 +0000 | [diff] [blame] | 148 | ON_CALL(*sMockBinding, fakeCreateSessionInternal).WillByDefault(Return(sessionPtr)); |
Igor Kraskevich | 2cec158 | 2024-03-13 11:23:40 +0000 | [diff] [blame] | 149 | ON_CALL(*sMockBinding, fakeSetThreads).WillByDefault(Return(0)); |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 150 | } |
| 151 | |
| 152 | void HintSessionWrapperTests::MockHintSessionBinding::init() { |
| 153 | sMockBinding->getManager = &stubGetManager; |
Matt Buckley | 27da134 | 2024-04-05 23:10:48 +0000 | [diff] [blame] | 154 | if (sMockBinding->createSessionInternal == nullptr) { |
| 155 | sMockBinding->createSessionInternal = &stubCreateSessionInternal; |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 156 | } |
| 157 | sMockBinding->closeSession = &stubCloseSession; |
| 158 | sMockBinding->updateTargetWorkDuration = &stubUpdateTargetWorkDuration; |
| 159 | sMockBinding->reportActualWorkDuration = &stubReportActualWorkDuration; |
| 160 | sMockBinding->sendHint = &stubSendHint; |
Igor Kraskevich | 2cec158 | 2024-03-13 11:23:40 +0000 | [diff] [blame] | 161 | sMockBinding->setThreads = &stubSetThreads; |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 162 | } |
| 163 | |
| 164 | void HintSessionWrapperTests::TearDown() { |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 165 | // Ensure that anything running on RT is completely finished |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 166 | mWrapper = nullptr; |
| 167 | sMockBinding = nullptr; |
| 168 | } |
| 169 | |
| 170 | TEST_F(HintSessionWrapperTests, destructorClosesBackgroundSession) { |
| 171 | EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(1); |
Matt Buckley | 27da134 | 2024-04-05 23:10:48 +0000 | [diff] [blame] | 172 | sMockBinding->createSessionInternal = stubSlowCreateSessionInternal; |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 173 | mWrapper->init(); |
| 174 | mWrapper = nullptr; |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 175 | Mock::VerifyAndClearExpectations(sMockBinding.get()); |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 176 | } |
| 177 | |
| 178 | TEST_F(HintSessionWrapperTests, sessionInitializesCorrectly) { |
Matt Buckley | 27da134 | 2024-04-05 23:10:48 +0000 | [diff] [blame] | 179 | EXPECT_CALL(*sMockBinding, fakeCreateSessionInternal(managerPtr, _, Gt(1), _, _)).Times(1); |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 180 | mWrapper->init(); |
| 181 | waitForWrapperReady(); |
| 182 | } |
| 183 | |
| 184 | TEST_F(HintSessionWrapperTests, loadUpHintsSendCorrectly) { |
| 185 | EXPECT_CALL(*sMockBinding, |
| 186 | fakeSendHint(sessionPtr, static_cast<int32_t>(SessionHint::CPU_LOAD_UP))) |
| 187 | .Times(1); |
| 188 | mWrapper->init(); |
| 189 | waitForWrapperReady(); |
| 190 | mWrapper->sendLoadIncreaseHint(); |
| 191 | } |
| 192 | |
| 193 | TEST_F(HintSessionWrapperTests, loadResetHintsSendCorrectly) { |
| 194 | EXPECT_CALL(*sMockBinding, |
| 195 | fakeSendHint(sessionPtr, static_cast<int32_t>(SessionHint::CPU_LOAD_RESET))) |
| 196 | .Times(1); |
| 197 | mWrapper->init(); |
| 198 | waitForWrapperReady(); |
| 199 | mWrapper->sendLoadResetHint(); |
| 200 | } |
| 201 | |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 202 | TEST_F(HintSessionWrapperTests, delayedDeletionWorksCorrectlyAndOnlyClosesOnce) { |
| 203 | EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(1); |
| 204 | mWrapper->init(); |
| 205 | waitForWrapperReady(); |
| 206 | // Init a second time just to ensure the wrapper grabs the promise value |
| 207 | mWrapper->init(); |
| 208 | |
| 209 | EXPECT_EQ(mWrapper->alive(), true); |
| 210 | |
| 211 | // Schedule delayed destruction, allow it to run, and check when it's done |
| 212 | scheduleDelayedDestroyManaged(); |
| 213 | allowDelayedDestructionToStart(); |
| 214 | waitForDelayedDestructionToFinish(); |
| 215 | |
| 216 | // Ensure it closed within the timeframe of the test |
| 217 | Mock::VerifyAndClearExpectations(sMockBinding.get()); |
| 218 | EXPECT_EQ(mWrapper->alive(), false); |
| 219 | // If we then delete the wrapper, it shouldn't close the session again |
| 220 | EXPECT_CALL(*sMockBinding, fakeCloseSession(_)).Times(0); |
| 221 | mWrapper = nullptr; |
| 222 | } |
| 223 | |
| 224 | TEST_F(HintSessionWrapperTests, delayedDeletionResolvesBeforeAsyncCreationFinishes) { |
| 225 | // Here we test whether queueing delayedDestroy works while creation is still happening, if |
| 226 | // creation happens after |
| 227 | EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(1); |
Matt Buckley | 27da134 | 2024-04-05 23:10:48 +0000 | [diff] [blame] | 228 | sMockBinding->createSessionInternal = &stubManagedCreateSessionInternal; |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 229 | |
| 230 | // Start creating the session and destroying it at the same time |
| 231 | mWrapper->init(); |
| 232 | scheduleDelayedDestroyManaged(); |
| 233 | |
| 234 | // Allow destruction to happen first |
| 235 | allowDelayedDestructionToStart(); |
| 236 | |
| 237 | // Make sure destruction has had time to happen |
| 238 | std::this_thread::sleep_for(50ms); |
| 239 | |
| 240 | // Then, allow creation to finish after delayed destroy runs |
| 241 | allowCreationToFinish(); |
| 242 | |
| 243 | // Wait for destruction to finish |
| 244 | waitForDelayedDestructionToFinish(); |
| 245 | |
| 246 | // Ensure it closed within the timeframe of the test |
| 247 | Mock::VerifyAndClearExpectations(sMockBinding.get()); |
| 248 | EXPECT_EQ(mWrapper->alive(), false); |
| 249 | } |
| 250 | |
| 251 | TEST_F(HintSessionWrapperTests, delayedDeletionResolvesAfterAsyncCreationFinishes) { |
| 252 | // Here we test whether queueing delayedDestroy works while creation is still happening, if |
| 253 | // creation happens before |
| 254 | EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(1); |
Matt Buckley | 27da134 | 2024-04-05 23:10:48 +0000 | [diff] [blame] | 255 | sMockBinding->createSessionInternal = &stubManagedCreateSessionInternal; |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 256 | |
| 257 | // Start creating the session and destroying it at the same time |
| 258 | mWrapper->init(); |
| 259 | scheduleDelayedDestroyManaged(); |
| 260 | |
| 261 | // Allow creation to happen first |
| 262 | allowCreationToFinish(); |
| 263 | |
| 264 | // Make sure creation has had time to happen |
| 265 | waitForWrapperReady(); |
| 266 | |
| 267 | // Then allow destruction to happen after creation is done |
| 268 | allowDelayedDestructionToStart(); |
| 269 | |
| 270 | // Wait for it to finish |
| 271 | waitForDelayedDestructionToFinish(); |
| 272 | |
| 273 | // Ensure it closed within the timeframe of the test |
| 274 | Mock::VerifyAndClearExpectations(sMockBinding.get()); |
| 275 | EXPECT_EQ(mWrapper->alive(), false); |
| 276 | } |
| 277 | |
| 278 | TEST_F(HintSessionWrapperTests, delayedDeletionDoesNotKillReusedSession) { |
| 279 | EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(0); |
Matt Buckley | cef0bca | 2023-10-16 22:00:11 +0000 | [diff] [blame] | 280 | EXPECT_CALL(*sMockBinding, fakeReportActualWorkDuration(sessionPtr, 5_ms)).Times(1); |
| 281 | |
| 282 | mWrapper->init(); |
| 283 | waitForWrapperReady(); |
| 284 | // Init a second time just to grab the wrapper from the promise |
| 285 | mWrapper->init(); |
| 286 | EXPECT_EQ(mWrapper->alive(), true); |
| 287 | |
| 288 | // First schedule the deletion |
| 289 | scheduleDelayedDestroyManaged(); |
| 290 | |
| 291 | // Then, report an actual duration |
| 292 | mWrapper->reportActualWorkDuration(5_ms); |
| 293 | |
| 294 | // Then, run the delayed deletion after sending the update |
| 295 | allowDelayedDestructionToStart(); |
| 296 | waitForDelayedDestructionToFinish(); |
| 297 | |
| 298 | // Ensure it didn't close within the timeframe of the test |
| 299 | Mock::VerifyAndClearExpectations(sMockBinding.get()); |
| 300 | EXPECT_EQ(mWrapper->alive(), true); |
| 301 | } |
| 302 | |
| 303 | TEST_F(HintSessionWrapperTests, loadUpDoesNotResetDeletionTimer) { |
| 304 | EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(1); |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 305 | EXPECT_CALL(*sMockBinding, |
| 306 | fakeSendHint(sessionPtr, static_cast<int32_t>(SessionHint::CPU_LOAD_UP))) |
| 307 | .Times(1); |
| 308 | |
| 309 | mWrapper->init(); |
| 310 | waitForWrapperReady(); |
| 311 | // Init a second time just to grab the wrapper from the promise |
| 312 | mWrapper->init(); |
| 313 | EXPECT_EQ(mWrapper->alive(), true); |
| 314 | |
| 315 | // First schedule the deletion |
| 316 | scheduleDelayedDestroyManaged(); |
| 317 | |
Matt Buckley | cef0bca | 2023-10-16 22:00:11 +0000 | [diff] [blame] | 318 | // Then, send a load_up hint |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 319 | mWrapper->sendLoadIncreaseHint(); |
| 320 | |
| 321 | // Then, run the delayed deletion after sending the update |
| 322 | allowDelayedDestructionToStart(); |
| 323 | waitForDelayedDestructionToFinish(); |
| 324 | |
Matt Buckley | cef0bca | 2023-10-16 22:00:11 +0000 | [diff] [blame] | 325 | // Ensure it closed within the timeframe of the test |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 326 | Mock::VerifyAndClearExpectations(sMockBinding.get()); |
Matt Buckley | cef0bca | 2023-10-16 22:00:11 +0000 | [diff] [blame] | 327 | EXPECT_EQ(mWrapper->alive(), false); |
| 328 | } |
| 329 | |
| 330 | TEST_F(HintSessionWrapperTests, manualSessionDestroyPlaysNiceWithDelayedDestruct) { |
| 331 | EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(1); |
| 332 | |
| 333 | mWrapper->init(); |
| 334 | waitForWrapperReady(); |
| 335 | // Init a second time just to grab the wrapper from the promise |
| 336 | mWrapper->init(); |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 337 | EXPECT_EQ(mWrapper->alive(), true); |
Matt Buckley | cef0bca | 2023-10-16 22:00:11 +0000 | [diff] [blame] | 338 | |
| 339 | // First schedule the deletion |
| 340 | scheduleDelayedDestroyManaged(); |
| 341 | |
| 342 | // Then, kill the session |
| 343 | mWrapper->destroy(); |
| 344 | |
| 345 | // Verify it died |
| 346 | Mock::VerifyAndClearExpectations(sMockBinding.get()); |
| 347 | EXPECT_EQ(mWrapper->alive(), false); |
| 348 | |
| 349 | EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(0); |
| 350 | |
| 351 | // Then, run the delayed deletion after manually killing the session |
| 352 | allowDelayedDestructionToStart(); |
| 353 | waitForDelayedDestructionToFinish(); |
| 354 | |
| 355 | // Ensure it didn't close again and is still dead |
| 356 | Mock::VerifyAndClearExpectations(sMockBinding.get()); |
| 357 | EXPECT_EQ(mWrapper->alive(), false); |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 358 | } |
| 359 | |
Igor Kraskevich | 2cec158 | 2024-03-13 11:23:40 +0000 | [diff] [blame] | 360 | TEST_F(HintSessionWrapperTests, setThreadsUpdatesSessionThreads) { |
Matt Buckley | 27da134 | 2024-04-05 23:10:48 +0000 | [diff] [blame] | 361 | EXPECT_CALL(*sMockBinding, fakeCreateSessionInternal(managerPtr, _, Gt(1), _, _)).Times(1); |
Igor Kraskevich | 2cec158 | 2024-03-13 11:23:40 +0000 | [diff] [blame] | 362 | EXPECT_CALL(*sMockBinding, fakeSetThreads(sessionPtr, testing::IsSupersetOf({11, 22}))) |
| 363 | .Times(1); |
| 364 | mWrapper->init(); |
| 365 | waitForWrapperReady(); |
| 366 | |
| 367 | // This changes the overall set of threads in the session, so the session wrapper should call |
| 368 | // setThreads. |
| 369 | mWrapper->setActiveFunctorThreads({11, 22}); |
| 370 | waitForSetThreadsReady(); |
| 371 | |
| 372 | // The set of threads doesn't change, so the session wrapper should not call setThreads this |
| 373 | // time. The order of the threads shouldn't matter. |
| 374 | mWrapper->setActiveFunctorThreads({22, 11}); |
| 375 | waitForSetThreadsReady(); |
| 376 | } |
| 377 | |
| 378 | TEST_F(HintSessionWrapperTests, setThreadsDoesntCrashAfterDestroy) { |
| 379 | EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(1); |
| 380 | |
| 381 | mWrapper->init(); |
| 382 | waitForWrapperReady(); |
| 383 | // Init a second time just to grab the wrapper from the promise |
| 384 | mWrapper->init(); |
| 385 | EXPECT_EQ(mWrapper->alive(), true); |
| 386 | |
| 387 | // Then, kill the session |
| 388 | mWrapper->destroy(); |
| 389 | |
| 390 | // Verify it died |
| 391 | Mock::VerifyAndClearExpectations(sMockBinding.get()); |
| 392 | EXPECT_EQ(mWrapper->alive(), false); |
| 393 | |
| 394 | // setActiveFunctorThreads shouldn't do anything, and shouldn't crash. |
| 395 | EXPECT_CALL(*sMockBinding, fakeSetThreads(_, _)).Times(0); |
| 396 | mWrapper->setActiveFunctorThreads({11, 22}); |
| 397 | waitForSetThreadsReady(); |
| 398 | } |
| 399 | |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 400 | } // namespace android::uirenderer::renderthread |