Send HWUI load reset hint when Choreographer registers a callback

Send a load reset hint hint to DrawFrameTask through ThreadedRenderer
from ViewRootImpl whenever Choreographer registers a callback. This
allows the PowerHAL to allocate more resources for HWUI in response to
upcoming work, helping prevent frame drop.

Bug: b/243938267
Test: manual

Change-Id: Ie2cf809cf85530af04f4d0db3407853d4da03d62
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index d77e882..164a494 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -587,6 +587,13 @@
         updateWebViewOverlayCallbacks();
     }
 
+    @Override
+    public void notifyCallbackPending() {
+        if (isEnabled()) {
+            super.notifyCallbackPending();
+        }
+    }
+
     /**
      * Updates the light position based on the position of the window.
      *
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 7e8ebd7..a28a86ac 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2308,6 +2308,7 @@
      */
     void notifyRendererOfFramePending() {
         if (mAttachInfo.mThreadedRenderer != null) {
+            mAttachInfo.mThreadedRenderer.notifyCallbackPending();
             mAttachInfo.mThreadedRenderer.notifyFramePending();
         }
     }
@@ -9125,6 +9126,9 @@
             mConsumeBatchedInputScheduled = true;
             mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
                     mConsumedBatchedInputRunnable, null);
+            if (mAttachInfo.mThreadedRenderer != null) {
+                mAttachInfo.mThreadedRenderer.notifyCallbackPending();
+            }
         }
     }
 
@@ -9318,6 +9322,9 @@
                 mViews.add(view);
                 postIfNeededLocked();
             }
+            if (mAttachInfo.mThreadedRenderer != null) {
+                mAttachInfo.mThreadedRenderer.notifyCallbackPending();
+            }
         }
 
         public void addViewRect(AttachInfo.InvalidateInfo info) {
@@ -9325,6 +9332,9 @@
                 mViewRects.add(info);
                 postIfNeededLocked();
             }
+            if (mAttachInfo.mThreadedRenderer != null) {
+                mAttachInfo.mThreadedRenderer.notifyCallbackPending();
+            }
         }
 
         public void removeView(View view) {
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index 48dd3e6..a7fb742 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -982,6 +982,15 @@
     }
 
     /**
+     * Notifies the hardware renderer about pending choreographer callbacks.
+     *
+     * @hide
+     */
+    public void notifyCallbackPending() {
+        nNotifyCallbackPending(mNativeProxy);
+    }
+
+    /**
      * b/68769804, b/66945974: For low FPS experiments.
      *
      * @hide
@@ -1536,4 +1545,6 @@
     private static native boolean nIsDrawingEnabled();
 
     private static native void nSetRtAnimationsEnabled(boolean rtAnimationsEnabled);
+
+    private static native void nNotifyCallbackPending(long nativeProxy);
 }
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index f603e23..0663121 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -860,6 +860,11 @@
     RenderProxy::setRtAnimationsEnabled(enabled);
 }
 
+static void android_view_ThreadedRenderer_notifyCallbackPending(JNIEnv*, jclass, jlong proxyPtr) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    proxy->notifyCallbackPending();
+}
+
 // Plumbs the display density down to DeviceInfo.
 static void android_view_ThreadedRenderer_setDisplayDensityDpi(JNIEnv*, jclass, jint densityDpi) {
     // Convert from dpi to density-independent pixels.
@@ -1037,6 +1042,8 @@
         {"nIsDrawingEnabled", "()Z", (void*)android_view_ThreadedRenderer_isDrawingEnabled},
         {"nSetRtAnimationsEnabled", "(Z)V",
          (void*)android_view_ThreadedRenderer_setRtAnimationsEnabled},
+        {"nNotifyCallbackPending", "(J)V",
+         (void*)android_view_ThreadedRenderer_notifyCallbackPending},
 };
 
 static JavaVM* mJvm = nullptr;
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index dc7676c..cb30614 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -42,6 +42,7 @@
                                                       size_t, int64_t);
 typedef void (*APH_updateTargetWorkDuration)(APerformanceHintSession*, int64_t);
 typedef void (*APH_reportActualWorkDuration)(APerformanceHintSession*, int64_t);
+typedef void (*APH_sendHint)(APerformanceHintSession* session, int32_t);
 typedef void (*APH_closeSession)(APerformanceHintSession* session);
 
 bool gAPerformanceHintBindingInitialized = false;
@@ -49,6 +50,7 @@
 APH_createSession gAPH_createSessionFn = nullptr;
 APH_updateTargetWorkDuration gAPH_updateTargetWorkDurationFn = nullptr;
 APH_reportActualWorkDuration gAPH_reportActualWorkDurationFn = nullptr;
+APH_sendHint gAPH_sendHintFn = nullptr;
 APH_closeSession gAPH_closeSessionFn = nullptr;
 
 void ensureAPerformanceHintBindingInitialized() {
@@ -77,6 +79,10 @@
             gAPH_reportActualWorkDurationFn == nullptr,
             "Failed to find required symbol APerformanceHint_reportActualWorkDuration!");
 
+    gAPH_sendHintFn = (APH_sendHint)dlsym(handle_, "APerformanceHint_sendHint");
+    LOG_ALWAYS_FATAL_IF(gAPH_sendHintFn == nullptr,
+                        "Failed to find required symbol APerformanceHint_sendHint!");
+
     gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession");
     LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr,
                         "Failed to find required symbol APerformanceHint_closeSession!");
@@ -239,6 +245,16 @@
     mLastDequeueBufferDuration = dequeueBufferDuration;
 }
 
+void DrawFrameTask::sendLoadResetHint() {
+    if (!(Properties::useHintManager && Properties::isDrawingEnabled())) return;
+    if (!mHintSessionWrapper) mHintSessionWrapper.emplace(mUiThreadId, mRenderThreadId);
+    nsecs_t now = systemTime();
+    if (now - mLastFrameNotification > kResetHintTimeout) {
+        mHintSessionWrapper->sendHint(SessionHint::CPU_LOAD_RESET);
+    }
+    mLastFrameNotification = now;
+}
+
 bool DrawFrameTask::syncFrameState(TreeInfo& info) {
     ATRACE_CALL();
     int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::Vsync)];
@@ -327,6 +343,12 @@
     }
 }
 
+void DrawFrameTask::HintSessionWrapper::sendHint(SessionHint hint) {
+    if (mHintSession && Properties::isDrawingEnabled()) {
+        gAPH_sendHintFn(mHintSession, static_cast<int>(hint));
+    }
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index d6fc292..7eae41c 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -28,6 +28,7 @@
 #include "../Rect.h"
 #include "../TreeInfo.h"
 #include "RenderTask.h"
+#include "utils/TimeUtils.h"
 
 namespace android {
 namespace uirenderer {
@@ -90,6 +91,8 @@
 
     void forceDrawNextFrame() { mForceDrawFrame = true; }
 
+    void sendLoadResetHint();
+
 private:
     class HintSessionWrapper {
     public:
@@ -98,6 +101,7 @@
 
         void updateTargetWorkDuration(long targetDurationNanos);
         void reportActualWorkDuration(long actualDurationNanos);
+        void sendHint(SessionHint hint);
 
     private:
         APerformanceHintSession* mHintSession = nullptr;
@@ -135,6 +139,9 @@
     nsecs_t mLastTargetWorkDuration = 0;
     std::optional<HintSessionWrapper> mHintSessionWrapper;
 
+    nsecs_t mLastFrameNotification = 0;
+    nsecs_t kResetHintTimeout = 100_ms;
+
     bool mForceDrawFrame = false;
 };
 
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 3324715..03a2bc9 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -236,6 +236,10 @@
     mRenderThread.queue().post([this]() { mContext->notifyFramePending(); });
 }
 
+void RenderProxy::notifyCallbackPending() {
+    mDrawFrameTask.sendLoadResetHint();
+}
+
 void RenderProxy::dumpProfileInfo(int fd, int dumpFlags) {
     mRenderThread.queue().runSync([&]() {
         std::lock_guard lock(mRenderThread.getJankDataMutex());
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 2a99a73..a21faa8 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -109,6 +109,7 @@
     static int maxTextureSize();
     void stopDrawing();
     void notifyFramePending();
+    void notifyCallbackPending();
 
     void dumpProfileInfo(int fd, int dumpFlags);
     // Not exported, only used for testing