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, ()); |
| 55 | MOCK_METHOD(APerformanceHintSession*, fakeCreateSession, |
| 56 | (APerformanceHintManager*, const int32_t*, size_t, int64_t)); |
| 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(); }; |
| 75 | static APerformanceHintSession* stubCreateSession(APerformanceHintManager* manager, |
| 76 | const int32_t* ids, size_t idsSize, |
| 77 | int64_t initialTarget) { |
| 78 | return sMockBinding->fakeCreateSession(manager, ids, idsSize, initialTarget); |
| 79 | } |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 80 | static APerformanceHintSession* stubManagedCreateSession(APerformanceHintManager* manager, |
| 81 | const int32_t* ids, size_t idsSize, |
| 82 | int64_t initialTarget) { |
| 83 | sMockBinding->allowCreationToFinish.get_future().wait(); |
| 84 | return sMockBinding->fakeCreateSession(manager, ids, idsSize, initialTarget); |
| 85 | } |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 86 | static APerformanceHintSession* stubSlowCreateSession(APerformanceHintManager* manager, |
| 87 | const int32_t* ids, size_t idsSize, |
| 88 | int64_t initialTarget) { |
| 89 | std::this_thread::sleep_for(50ms); |
| 90 | return sMockBinding->fakeCreateSession(manager, ids, idsSize, initialTarget); |
| 91 | } |
| 92 | static void stubCloseSession(APerformanceHintSession* session) { |
| 93 | sMockBinding->fakeCloseSession(session); |
| 94 | }; |
| 95 | static void stubUpdateTargetWorkDuration(APerformanceHintSession* session, |
| 96 | int64_t workDuration) { |
| 97 | sMockBinding->fakeUpdateTargetWorkDuration(session, workDuration); |
| 98 | } |
| 99 | static void stubReportActualWorkDuration(APerformanceHintSession* session, |
| 100 | int64_t workDuration) { |
| 101 | sMockBinding->fakeReportActualWorkDuration(session, workDuration); |
| 102 | } |
| 103 | static void stubSendHint(APerformanceHintSession* session, int32_t hintId) { |
| 104 | sMockBinding->fakeSendHint(session, hintId); |
| 105 | }; |
Igor Kraskevich | 2cec158 | 2024-03-13 11:23:40 +0000 | [diff] [blame^] | 106 | static int stubSetThreads(APerformanceHintSession* session, const pid_t* ids, size_t size) { |
| 107 | std::vector<pid_t> tids(ids, ids + size); |
| 108 | return sMockBinding->fakeSetThreads(session, tids); |
| 109 | } |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 110 | void waitForWrapperReady() { |
| 111 | if (mWrapper->mHintSessionFuture.has_value()) { |
| 112 | mWrapper->mHintSessionFuture->wait(); |
| 113 | } |
| 114 | } |
Igor Kraskevich | 2cec158 | 2024-03-13 11:23:40 +0000 | [diff] [blame^] | 115 | void waitForSetThreadsReady() { |
| 116 | if (mWrapper->mSetThreadsFuture.has_value()) { |
| 117 | mWrapper->mSetThreadsFuture->wait(); |
| 118 | } |
| 119 | } |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 120 | void scheduleDelayedDestroyManaged() { |
| 121 | TestUtils::runOnRenderThread([&](renderthread::RenderThread& rt) { |
| 122 | // Guaranteed to be scheduled first, allows destruction to start |
| 123 | rt.queue().postDelayed(0_ms, [&] { blockDestroyCallUntil.get_future().wait(); }); |
| 124 | // Guaranteed to be scheduled second, destroys the session |
| 125 | mWrapper->delayedDestroy(rt, 1_ms, mWrapper); |
| 126 | // This is guaranteed to be queued after the destroy, signals that destruction is done |
| 127 | rt.queue().postDelayed(1_ms, [&] { waitForDestroyFinished.set_value(1); }); |
| 128 | }); |
| 129 | } |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 130 | }; |
| 131 | |
| 132 | std::shared_ptr<HintSessionWrapperTests::MockHintSessionBinding> |
| 133 | HintSessionWrapperTests::sMockBinding; |
| 134 | |
| 135 | void HintSessionWrapperTests::SetUp() { |
| 136 | // Pretend it's supported even if we're in an emulator |
| 137 | Properties::useHintManager = true; |
| 138 | sMockBinding = std::make_shared<NiceMock<MockHintSessionBinding>>(); |
| 139 | mWrapper = std::make_shared<HintSessionWrapper>(uiThreadId, renderThreadId); |
| 140 | mWrapper->mBinding = sMockBinding; |
| 141 | EXPECT_CALL(*sMockBinding, fakeGetManager).WillOnce(Return(managerPtr)); |
| 142 | ON_CALL(*sMockBinding, fakeCreateSession).WillByDefault(Return(sessionPtr)); |
Igor Kraskevich | 2cec158 | 2024-03-13 11:23:40 +0000 | [diff] [blame^] | 143 | ON_CALL(*sMockBinding, fakeSetThreads).WillByDefault(Return(0)); |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 144 | } |
| 145 | |
| 146 | void HintSessionWrapperTests::MockHintSessionBinding::init() { |
| 147 | sMockBinding->getManager = &stubGetManager; |
| 148 | if (sMockBinding->createSession == nullptr) { |
| 149 | sMockBinding->createSession = &stubCreateSession; |
| 150 | } |
| 151 | sMockBinding->closeSession = &stubCloseSession; |
| 152 | sMockBinding->updateTargetWorkDuration = &stubUpdateTargetWorkDuration; |
| 153 | sMockBinding->reportActualWorkDuration = &stubReportActualWorkDuration; |
| 154 | sMockBinding->sendHint = &stubSendHint; |
Igor Kraskevich | 2cec158 | 2024-03-13 11:23:40 +0000 | [diff] [blame^] | 155 | sMockBinding->setThreads = &stubSetThreads; |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 156 | } |
| 157 | |
| 158 | void HintSessionWrapperTests::TearDown() { |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 159 | // Ensure that anything running on RT is completely finished |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 160 | mWrapper = nullptr; |
| 161 | sMockBinding = nullptr; |
| 162 | } |
| 163 | |
| 164 | TEST_F(HintSessionWrapperTests, destructorClosesBackgroundSession) { |
| 165 | EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(1); |
| 166 | sMockBinding->createSession = stubSlowCreateSession; |
| 167 | mWrapper->init(); |
| 168 | mWrapper = nullptr; |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 169 | Mock::VerifyAndClearExpectations(sMockBinding.get()); |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 170 | } |
| 171 | |
| 172 | TEST_F(HintSessionWrapperTests, sessionInitializesCorrectly) { |
| 173 | EXPECT_CALL(*sMockBinding, fakeCreateSession(managerPtr, _, Gt(1), _)).Times(1); |
| 174 | mWrapper->init(); |
| 175 | waitForWrapperReady(); |
| 176 | } |
| 177 | |
| 178 | TEST_F(HintSessionWrapperTests, loadUpHintsSendCorrectly) { |
| 179 | EXPECT_CALL(*sMockBinding, |
| 180 | fakeSendHint(sessionPtr, static_cast<int32_t>(SessionHint::CPU_LOAD_UP))) |
| 181 | .Times(1); |
| 182 | mWrapper->init(); |
| 183 | waitForWrapperReady(); |
| 184 | mWrapper->sendLoadIncreaseHint(); |
| 185 | } |
| 186 | |
| 187 | TEST_F(HintSessionWrapperTests, loadResetHintsSendCorrectly) { |
| 188 | EXPECT_CALL(*sMockBinding, |
| 189 | fakeSendHint(sessionPtr, static_cast<int32_t>(SessionHint::CPU_LOAD_RESET))) |
| 190 | .Times(1); |
| 191 | mWrapper->init(); |
| 192 | waitForWrapperReady(); |
| 193 | mWrapper->sendLoadResetHint(); |
| 194 | } |
| 195 | |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 196 | TEST_F(HintSessionWrapperTests, delayedDeletionWorksCorrectlyAndOnlyClosesOnce) { |
| 197 | EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(1); |
| 198 | mWrapper->init(); |
| 199 | waitForWrapperReady(); |
| 200 | // Init a second time just to ensure the wrapper grabs the promise value |
| 201 | mWrapper->init(); |
| 202 | |
| 203 | EXPECT_EQ(mWrapper->alive(), true); |
| 204 | |
| 205 | // Schedule delayed destruction, allow it to run, and check when it's done |
| 206 | scheduleDelayedDestroyManaged(); |
| 207 | allowDelayedDestructionToStart(); |
| 208 | waitForDelayedDestructionToFinish(); |
| 209 | |
| 210 | // Ensure it closed within the timeframe of the test |
| 211 | Mock::VerifyAndClearExpectations(sMockBinding.get()); |
| 212 | EXPECT_EQ(mWrapper->alive(), false); |
| 213 | // If we then delete the wrapper, it shouldn't close the session again |
| 214 | EXPECT_CALL(*sMockBinding, fakeCloseSession(_)).Times(0); |
| 215 | mWrapper = nullptr; |
| 216 | } |
| 217 | |
| 218 | TEST_F(HintSessionWrapperTests, delayedDeletionResolvesBeforeAsyncCreationFinishes) { |
| 219 | // Here we test whether queueing delayedDestroy works while creation is still happening, if |
| 220 | // creation happens after |
| 221 | EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(1); |
| 222 | sMockBinding->createSession = &stubManagedCreateSession; |
| 223 | |
| 224 | // Start creating the session and destroying it at the same time |
| 225 | mWrapper->init(); |
| 226 | scheduleDelayedDestroyManaged(); |
| 227 | |
| 228 | // Allow destruction to happen first |
| 229 | allowDelayedDestructionToStart(); |
| 230 | |
| 231 | // Make sure destruction has had time to happen |
| 232 | std::this_thread::sleep_for(50ms); |
| 233 | |
| 234 | // Then, allow creation to finish after delayed destroy runs |
| 235 | allowCreationToFinish(); |
| 236 | |
| 237 | // Wait for destruction to finish |
| 238 | waitForDelayedDestructionToFinish(); |
| 239 | |
| 240 | // Ensure it closed within the timeframe of the test |
| 241 | Mock::VerifyAndClearExpectations(sMockBinding.get()); |
| 242 | EXPECT_EQ(mWrapper->alive(), false); |
| 243 | } |
| 244 | |
| 245 | TEST_F(HintSessionWrapperTests, delayedDeletionResolvesAfterAsyncCreationFinishes) { |
| 246 | // Here we test whether queueing delayedDestroy works while creation is still happening, if |
| 247 | // creation happens before |
| 248 | EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(1); |
| 249 | sMockBinding->createSession = &stubManagedCreateSession; |
| 250 | |
| 251 | // Start creating the session and destroying it at the same time |
| 252 | mWrapper->init(); |
| 253 | scheduleDelayedDestroyManaged(); |
| 254 | |
| 255 | // Allow creation to happen first |
| 256 | allowCreationToFinish(); |
| 257 | |
| 258 | // Make sure creation has had time to happen |
| 259 | waitForWrapperReady(); |
| 260 | |
| 261 | // Then allow destruction to happen after creation is done |
| 262 | allowDelayedDestructionToStart(); |
| 263 | |
| 264 | // Wait for it to finish |
| 265 | waitForDelayedDestructionToFinish(); |
| 266 | |
| 267 | // Ensure it closed within the timeframe of the test |
| 268 | Mock::VerifyAndClearExpectations(sMockBinding.get()); |
| 269 | EXPECT_EQ(mWrapper->alive(), false); |
| 270 | } |
| 271 | |
| 272 | TEST_F(HintSessionWrapperTests, delayedDeletionDoesNotKillReusedSession) { |
| 273 | EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(0); |
Matt Buckley | cef0bca | 2023-10-16 22:00:11 +0000 | [diff] [blame] | 274 | EXPECT_CALL(*sMockBinding, fakeReportActualWorkDuration(sessionPtr, 5_ms)).Times(1); |
| 275 | |
| 276 | mWrapper->init(); |
| 277 | waitForWrapperReady(); |
| 278 | // Init a second time just to grab the wrapper from the promise |
| 279 | mWrapper->init(); |
| 280 | EXPECT_EQ(mWrapper->alive(), true); |
| 281 | |
| 282 | // First schedule the deletion |
| 283 | scheduleDelayedDestroyManaged(); |
| 284 | |
| 285 | // Then, report an actual duration |
| 286 | mWrapper->reportActualWorkDuration(5_ms); |
| 287 | |
| 288 | // Then, run the delayed deletion after sending the update |
| 289 | allowDelayedDestructionToStart(); |
| 290 | waitForDelayedDestructionToFinish(); |
| 291 | |
| 292 | // Ensure it didn't close within the timeframe of the test |
| 293 | Mock::VerifyAndClearExpectations(sMockBinding.get()); |
| 294 | EXPECT_EQ(mWrapper->alive(), true); |
| 295 | } |
| 296 | |
| 297 | TEST_F(HintSessionWrapperTests, loadUpDoesNotResetDeletionTimer) { |
| 298 | EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(1); |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 299 | EXPECT_CALL(*sMockBinding, |
| 300 | fakeSendHint(sessionPtr, static_cast<int32_t>(SessionHint::CPU_LOAD_UP))) |
| 301 | .Times(1); |
| 302 | |
| 303 | mWrapper->init(); |
| 304 | waitForWrapperReady(); |
| 305 | // Init a second time just to grab the wrapper from the promise |
| 306 | mWrapper->init(); |
| 307 | EXPECT_EQ(mWrapper->alive(), true); |
| 308 | |
| 309 | // First schedule the deletion |
| 310 | scheduleDelayedDestroyManaged(); |
| 311 | |
Matt Buckley | cef0bca | 2023-10-16 22:00:11 +0000 | [diff] [blame] | 312 | // Then, send a load_up hint |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 313 | mWrapper->sendLoadIncreaseHint(); |
| 314 | |
| 315 | // Then, run the delayed deletion after sending the update |
| 316 | allowDelayedDestructionToStart(); |
| 317 | waitForDelayedDestructionToFinish(); |
| 318 | |
Matt Buckley | cef0bca | 2023-10-16 22:00:11 +0000 | [diff] [blame] | 319 | // Ensure it closed within the timeframe of the test |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 320 | Mock::VerifyAndClearExpectations(sMockBinding.get()); |
Matt Buckley | cef0bca | 2023-10-16 22:00:11 +0000 | [diff] [blame] | 321 | EXPECT_EQ(mWrapper->alive(), false); |
| 322 | } |
| 323 | |
| 324 | TEST_F(HintSessionWrapperTests, manualSessionDestroyPlaysNiceWithDelayedDestruct) { |
| 325 | EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(1); |
| 326 | |
| 327 | mWrapper->init(); |
| 328 | waitForWrapperReady(); |
| 329 | // Init a second time just to grab the wrapper from the promise |
| 330 | mWrapper->init(); |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 331 | EXPECT_EQ(mWrapper->alive(), true); |
Matt Buckley | cef0bca | 2023-10-16 22:00:11 +0000 | [diff] [blame] | 332 | |
| 333 | // First schedule the deletion |
| 334 | scheduleDelayedDestroyManaged(); |
| 335 | |
| 336 | // Then, kill the session |
| 337 | mWrapper->destroy(); |
| 338 | |
| 339 | // Verify it died |
| 340 | Mock::VerifyAndClearExpectations(sMockBinding.get()); |
| 341 | EXPECT_EQ(mWrapper->alive(), false); |
| 342 | |
| 343 | EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(0); |
| 344 | |
| 345 | // Then, run the delayed deletion after manually killing the session |
| 346 | allowDelayedDestructionToStart(); |
| 347 | waitForDelayedDestructionToFinish(); |
| 348 | |
| 349 | // Ensure it didn't close again and is still dead |
| 350 | Mock::VerifyAndClearExpectations(sMockBinding.get()); |
| 351 | EXPECT_EQ(mWrapper->alive(), false); |
Matt Buckley | 0daae6a | 2023-09-14 22:56:50 +0000 | [diff] [blame] | 352 | } |
| 353 | |
Igor Kraskevich | 2cec158 | 2024-03-13 11:23:40 +0000 | [diff] [blame^] | 354 | TEST_F(HintSessionWrapperTests, setThreadsUpdatesSessionThreads) { |
| 355 | EXPECT_CALL(*sMockBinding, fakeCreateSession(managerPtr, _, Gt(1), _)).Times(1); |
| 356 | EXPECT_CALL(*sMockBinding, fakeSetThreads(sessionPtr, testing::IsSupersetOf({11, 22}))) |
| 357 | .Times(1); |
| 358 | mWrapper->init(); |
| 359 | waitForWrapperReady(); |
| 360 | |
| 361 | // This changes the overall set of threads in the session, so the session wrapper should call |
| 362 | // setThreads. |
| 363 | mWrapper->setActiveFunctorThreads({11, 22}); |
| 364 | waitForSetThreadsReady(); |
| 365 | |
| 366 | // The set of threads doesn't change, so the session wrapper should not call setThreads this |
| 367 | // time. The order of the threads shouldn't matter. |
| 368 | mWrapper->setActiveFunctorThreads({22, 11}); |
| 369 | waitForSetThreadsReady(); |
| 370 | } |
| 371 | |
| 372 | TEST_F(HintSessionWrapperTests, setThreadsDoesntCrashAfterDestroy) { |
| 373 | EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(1); |
| 374 | |
| 375 | mWrapper->init(); |
| 376 | waitForWrapperReady(); |
| 377 | // Init a second time just to grab the wrapper from the promise |
| 378 | mWrapper->init(); |
| 379 | EXPECT_EQ(mWrapper->alive(), true); |
| 380 | |
| 381 | // Then, kill the session |
| 382 | mWrapper->destroy(); |
| 383 | |
| 384 | // Verify it died |
| 385 | Mock::VerifyAndClearExpectations(sMockBinding.get()); |
| 386 | EXPECT_EQ(mWrapper->alive(), false); |
| 387 | |
| 388 | // setActiveFunctorThreads shouldn't do anything, and shouldn't crash. |
| 389 | EXPECT_CALL(*sMockBinding, fakeSetThreads(_, _)).Times(0); |
| 390 | mWrapper->setActiveFunctorThreads({11, 22}); |
| 391 | waitForSetThreadsReady(); |
| 392 | } |
| 393 | |
Matt Buckley | 0c66836 | 2023-09-07 05:52:07 +0000 | [diff] [blame] | 394 | } // namespace android::uirenderer::renderthread |