Optimize HWUI ADPF for sysui and ensure correct closure

This patch prevents the HintSessionWrapper from setting the
timestamp on load_up hints, to avoid edge cases in systemui
where load_up hints were being sent before reset had a chance
to be checked, making ADPF think work was still ongoing.

This patch also ensures the session closes when a
CanvasContext is destructed, as previously it would wait until
the delayed destroy was evaluated before closing the session.

Bug: 302620048
Test: hwuiunit
Change-Id: I15172382665934acc28c80ff06937475481ba62b
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index b00fc69..14602ef 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -139,6 +139,7 @@
     mRenderNodes.clear();
     mRenderThread.cacheManager().unregisterCanvasContext(this);
     mRenderThread.renderState().removeContextCallback(this);
+    mHintSessionWrapper->destroy();
 }
 
 void CanvasContext::addRenderNode(RenderNode* node, bool placeFront) {
diff --git a/libs/hwui/renderthread/HintSessionWrapper.cpp b/libs/hwui/renderthread/HintSessionWrapper.cpp
index 1c3399a..2362331 100644
--- a/libs/hwui/renderthread/HintSessionWrapper.cpp
+++ b/libs/hwui/renderthread/HintSessionWrapper.cpp
@@ -158,7 +158,6 @@
 void HintSessionWrapper::sendLoadIncreaseHint() {
     if (!init()) return;
     mBinding->sendHint(mHintSession, static_cast<int32_t>(SessionHint::CPU_LOAD_UP));
-    mLastFrameNotification = systemTime();
 }
 
 bool HintSessionWrapper::alive() {
diff --git a/libs/hwui/tests/unit/HintSessionWrapperTests.cpp b/libs/hwui/tests/unit/HintSessionWrapperTests.cpp
index a14ae1c..10a740a 100644
--- a/libs/hwui/tests/unit/HintSessionWrapperTests.cpp
+++ b/libs/hwui/tests/unit/HintSessionWrapperTests.cpp
@@ -259,6 +259,31 @@
 
 TEST_F(HintSessionWrapperTests, delayedDeletionDoesNotKillReusedSession) {
     EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(0);
+    EXPECT_CALL(*sMockBinding, fakeReportActualWorkDuration(sessionPtr, 5_ms)).Times(1);
+
+    mWrapper->init();
+    waitForWrapperReady();
+    // Init a second time just to grab the wrapper from the promise
+    mWrapper->init();
+    EXPECT_EQ(mWrapper->alive(), true);
+
+    // First schedule the deletion
+    scheduleDelayedDestroyManaged();
+
+    // Then, report an actual duration
+    mWrapper->reportActualWorkDuration(5_ms);
+
+    // Then, run the delayed deletion after sending the update
+    allowDelayedDestructionToStart();
+    waitForDelayedDestructionToFinish();
+
+    // Ensure it didn't close within the timeframe of the test
+    Mock::VerifyAndClearExpectations(sMockBinding.get());
+    EXPECT_EQ(mWrapper->alive(), true);
+}
+
+TEST_F(HintSessionWrapperTests, loadUpDoesNotResetDeletionTimer) {
+    EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(1);
     EXPECT_CALL(*sMockBinding,
                 fakeSendHint(sessionPtr, static_cast<int32_t>(SessionHint::CPU_LOAD_UP)))
             .Times(1);
@@ -272,16 +297,46 @@
     // First schedule the deletion
     scheduleDelayedDestroyManaged();
 
-    // Then, send a hint to update the timestamp
+    // Then, send a load_up hint
     mWrapper->sendLoadIncreaseHint();
 
     // Then, run the delayed deletion after sending the update
     allowDelayedDestructionToStart();
     waitForDelayedDestructionToFinish();
 
-    // Ensure it didn't close within the timeframe of the test
+    // Ensure it closed within the timeframe of the test
     Mock::VerifyAndClearExpectations(sMockBinding.get());
+    EXPECT_EQ(mWrapper->alive(), false);
+}
+
+TEST_F(HintSessionWrapperTests, manualSessionDestroyPlaysNiceWithDelayedDestruct) {
+    EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(1);
+
+    mWrapper->init();
+    waitForWrapperReady();
+    // Init a second time just to grab the wrapper from the promise
+    mWrapper->init();
     EXPECT_EQ(mWrapper->alive(), true);
+
+    // First schedule the deletion
+    scheduleDelayedDestroyManaged();
+
+    // Then, kill the session
+    mWrapper->destroy();
+
+    // Verify it died
+    Mock::VerifyAndClearExpectations(sMockBinding.get());
+    EXPECT_EQ(mWrapper->alive(), false);
+
+    EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(0);
+
+    // Then, run the delayed deletion after manually killing the session
+    allowDelayedDestructionToStart();
+    waitForDelayedDestructionToFinish();
+
+    // Ensure it didn't close again and is still dead
+    Mock::VerifyAndClearExpectations(sMockBinding.get());
+    EXPECT_EQ(mWrapper->alive(), false);
 }
 
 }  // namespace android::uirenderer::renderthread
\ No newline at end of file