diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java index fe04f0dd4c83e..c3b1cd74d29b0 100644 --- a/graphics/java/android/graphics/HardwareRenderer.java +++ b/graphics/java/android/graphics/HardwareRenderer.java @@ -28,7 +28,6 @@ import android.content.res.Configuration; import android.hardware.display.DisplayManager; import android.os.IBinder; import android.os.ParcelFileDescriptor; -import android.os.PerformanceHintManager; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; @@ -856,36 +855,6 @@ public class HardwareRenderer { callback.onPictureCaptured(picture); } - /** called by native */ - static PerformanceHintManager.Session createHintSession(int[] tids) { - PerformanceHintManager performanceHintManager = - ProcessInitializer.sInstance.getHintManager(); - if (performanceHintManager == null) { - return null; - } - // Native code will always set a target duration before reporting actual durations. - // So this is just a placeholder value that's never used. - long targetDurationNanos = 16666667; - return performanceHintManager.createHintSession(tids, targetDurationNanos); - } - - /** called by native */ - static void updateTargetWorkDuration(PerformanceHintManager.Session session, - long targetDurationNanos) { - session.updateTargetWorkDuration(targetDurationNanos); - } - - /** called by native */ - static void reportActualWorkDuration(PerformanceHintManager.Session session, - long actualDurationNanos) { - session.reportActualWorkDuration(actualDurationNanos); - } - - /** called by native */ - static void closeHintSession(PerformanceHintManager.Session session) { - session.close(); - } - /** * Interface used to receive callbacks when Webview requests a surface control. * @@ -1152,7 +1121,6 @@ public class HardwareRenderer { private boolean mIsolated = false; private Context mContext; private String mPackageName; - private PerformanceHintManager mPerformanceHintManager; private IGraphicsStats mGraphicsStatsService; private IGraphicsStatsCallback mGraphicsStatsCallback = new IGraphicsStatsCallback.Stub() { @Override @@ -1164,10 +1132,6 @@ public class HardwareRenderer { private ProcessInitializer() { } - synchronized PerformanceHintManager getHintManager() { - return mPerformanceHintManager; - } - synchronized void setPackageName(String name) { if (mInitialized) return; mPackageName = name; @@ -1218,10 +1182,6 @@ public class HardwareRenderer { initDisplayInfo(); - // HintManager and HintSession are designed to be accessible from isoalted processes - // so not checking for isolated process here. - initHintSession(); - nSetIsHighEndGfx(ActivityManager.isHighEndGfx()); // Defensively clear out the context in case we were passed a context that can leak // if we live longer than it, e.g. an activity context. @@ -1265,11 +1225,6 @@ public class HardwareRenderer { mDisplayInitialized = true; } - private void initHintSession() { - if (mContext == null) return; - mPerformanceHintManager = mContext.getSystemService(PerformanceHintManager.class); - } - private void rotateBuffer() { nRotateProcessStatsBuffer(); requestBuffer(); diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp index c4cdb7db7d866..54367b8334cbd 100644 --- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp +++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp @@ -44,8 +44,6 @@ #include #include -#include - #include #include #include @@ -60,10 +58,6 @@ using namespace android::uirenderer::renderthread; struct { jclass clazz; jmethodID invokePictureCapturedCallback; - jmethodID createHintSession; - jmethodID updateTargetWorkDuration; - jmethodID reportActualWorkDuration; - jmethodID closeHintSession; } gHardwareRenderer; struct { @@ -90,14 +84,6 @@ static JNIEnv* getenv(JavaVM* vm) { return env; } -static bool hasExceptionAndClear(JNIEnv* env) { - if (GraphicsJNI::hasException(env)) { - env->ExceptionClear(); - return true; - } - return false; -} - typedef ANativeWindow* (*ANW_fromSurface)(JNIEnv* env, jobject surface); ANW_fromSurface fromSurface; @@ -147,67 +133,6 @@ private: } }; -class HintSessionWrapper : public LightRefBase { -public: - static sp create(JNIEnv* env, RenderProxy* proxy) { - if (!Properties::useHintManager) return nullptr; - - // Include UI thread (self), render thread, and thread pool. - std::vector tids = CommonPool::getThreadIds(); - tids.push_back(proxy->getRenderThreadTid()); - tids.push_back(pthread_gettid_np(pthread_self())); - - jintArray tidsArray = env->NewIntArray(tids.size()); - if (hasExceptionAndClear(env)) return nullptr; - env->SetIntArrayRegion(tidsArray, 0, tids.size(), reinterpret_cast(tids.data())); - if (hasExceptionAndClear(env)) return nullptr; - jobject session = env->CallStaticObjectMethod( - gHardwareRenderer.clazz, gHardwareRenderer.createHintSession, tidsArray); - if (hasExceptionAndClear(env) || !session) return nullptr; - return new HintSessionWrapper(env, session); - } - - ~HintSessionWrapper() { - if (!mSession) return; - JNIEnv* env = getenv(mVm); - env->CallStaticVoidMethod(gHardwareRenderer.clazz, gHardwareRenderer.closeHintSession, - mSession); - hasExceptionAndClear(env); - env->DeleteGlobalRef(mSession); - mSession = nullptr; - } - - void updateTargetWorkDuration(long targetDurationNanos) { - if (!mSession) return; - JNIEnv* env = getenv(mVm); - env->CallStaticVoidMethod(gHardwareRenderer.clazz, - gHardwareRenderer.updateTargetWorkDuration, mSession, - static_cast(targetDurationNanos)); - hasExceptionAndClear(env); - } - - void reportActualWorkDuration(long actualDurationNanos) { - if (!mSession) return; - JNIEnv* env = getenv(mVm); - env->CallStaticVoidMethod(gHardwareRenderer.clazz, - gHardwareRenderer.reportActualWorkDuration, mSession, - static_cast(actualDurationNanos)); - hasExceptionAndClear(env); - } - -private: - HintSessionWrapper(JNIEnv* env, jobject jobject) { - env->GetJavaVM(&mVm); - if (jobject) { - mSession = env->NewGlobalRef(jobject); - LOG_ALWAYS_FATAL_IF(!mSession, "Failed to make global ref"); - } - } - - JavaVM* mVm = nullptr; - jobject mSession = nullptr; -}; - static void android_view_ThreadedRenderer_rotateProcessStatsBuffer(JNIEnv* env, jobject clazz) { RenderProxy::rotateProcessStatsBuffer(); } @@ -235,12 +160,6 @@ static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject claz RootRenderNode* rootRenderNode = reinterpret_cast(rootRenderNodePtr); ContextFactoryImpl factory(rootRenderNode); RenderProxy* proxy = new RenderProxy(translucent, rootRenderNode, &factory); - sp wrapper = HintSessionWrapper::create(env, proxy); - if (wrapper) { - proxy->setHintSessionCallbacks( - [wrapper](int64_t nanos) { wrapper->updateTargetWorkDuration(nanos); }, - [wrapper](int64_t nanos) { wrapper->reportActualWorkDuration(nanos); }); - } return (jlong) proxy; } @@ -1059,18 +978,6 @@ int register_android_view_ThreadedRenderer(JNIEnv* env) { gHardwareRenderer.invokePictureCapturedCallback = GetStaticMethodIDOrDie(env, hardwareRenderer, "invokePictureCapturedCallback", "(JLandroid/graphics/HardwareRenderer$PictureCapturedCallback;)V"); - gHardwareRenderer.createHintSession = - GetStaticMethodIDOrDie(env, hardwareRenderer, "createHintSession", - "([I)Landroid/os/PerformanceHintManager$Session;"); - gHardwareRenderer.updateTargetWorkDuration = - GetStaticMethodIDOrDie(env, hardwareRenderer, "updateTargetWorkDuration", - "(Landroid/os/PerformanceHintManager$Session;J)V"); - gHardwareRenderer.reportActualWorkDuration = - GetStaticMethodIDOrDie(env, hardwareRenderer, "reportActualWorkDuration", - "(Landroid/os/PerformanceHintManager$Session;J)V"); - gHardwareRenderer.closeHintSession = - GetStaticMethodIDOrDie(env, hardwareRenderer, "closeHintSession", - "(Landroid/os/PerformanceHintManager$Session;)V"); jclass aSurfaceTransactionCallbackClass = FindClassOrDie(env, "android/graphics/HardwareRenderer$ASurfaceTransactionCallback"); diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index db29e342855bb..e7081df2b558d 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -16,6 +16,7 @@ #include "DrawFrameTask.h" +#include #include #include #include @@ -26,11 +27,63 @@ #include "../RenderNode.h" #include "CanvasContext.h" #include "RenderThread.h" +#include "thread/CommonPool.h" namespace android { namespace uirenderer { namespace renderthread { +namespace { + +typedef APerformanceHintManager* (*APH_getManager)(); +typedef APerformanceHintSession* (*APH_createSession)(APerformanceHintManager*, const int32_t*, + size_t, int64_t); +typedef void (*APH_updateTargetWorkDuration)(APerformanceHintSession*, int64_t); +typedef void (*APH_reportActualWorkDuration)(APerformanceHintSession*, int64_t); +typedef void (*APH_closeSession)(APerformanceHintSession* session); + +bool gAPerformanceHintBindingInitialized = false; +APH_getManager gAPH_getManagerFn = nullptr; +APH_createSession gAPH_createSessionFn = nullptr; +APH_updateTargetWorkDuration gAPH_updateTargetWorkDurationFn = nullptr; +APH_reportActualWorkDuration gAPH_reportActualWorkDurationFn = nullptr; +APH_closeSession gAPH_closeSessionFn = nullptr; + +void ensureAPerformanceHintBindingInitialized() { + if (gAPerformanceHintBindingInitialized) return; + + void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE); + LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!"); + + gAPH_getManagerFn = (APH_getManager)dlsym(handle_, "APerformanceHint_getManager"); + LOG_ALWAYS_FATAL_IF(gAPH_getManagerFn == nullptr, + "Failed to find required symbol APerformanceHint_getManager!"); + + gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession"); + LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr, + "Failed to find required symbol APerformanceHint_createSession!"); + + gAPH_updateTargetWorkDurationFn = (APH_updateTargetWorkDuration)dlsym( + handle_, "APerformanceHint_updateTargetWorkDuration"); + LOG_ALWAYS_FATAL_IF( + gAPH_updateTargetWorkDurationFn == nullptr, + "Failed to find required symbol APerformanceHint_updateTargetWorkDuration!"); + + gAPH_reportActualWorkDurationFn = (APH_reportActualWorkDuration)dlsym( + handle_, "APerformanceHint_reportActualWorkDuration"); + LOG_ALWAYS_FATAL_IF( + gAPH_reportActualWorkDurationFn == nullptr, + "Failed to find required symbol APerformanceHint_reportActualWorkDuration!"); + + gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession"); + LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr, + "Failed to find required symbol APerformanceHint_closeSession!"); + + gAPerformanceHintBindingInitialized = true; +} + +} // namespace + DrawFrameTask::DrawFrameTask() : mRenderThread(nullptr) , mContext(nullptr) @@ -39,17 +92,13 @@ DrawFrameTask::DrawFrameTask() DrawFrameTask::~DrawFrameTask() {} -void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context, - RenderNode* targetNode) { +void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode, + int32_t uiThreadId, int32_t renderThreadId) { mRenderThread = thread; mContext = context; mTargetNode = targetNode; -} - -void DrawFrameTask::setHintSessionCallbacks(std::function updateTargetWorkDuration, - std::function reportActualWorkDuration) { - mUpdateTargetWorkDuration = std::move(updateTargetWorkDuration); - mReportActualWorkDuration = std::move(reportActualWorkDuration); + mUiThreadId = uiThreadId; + mRenderThreadId = renderThreadId; } void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) { @@ -144,27 +193,25 @@ void DrawFrameTask::run() { unblockUiThread(); } - // These member callbacks are effectively const as they are set once during init, so it's safe - // to use these directly instead of making local copies. - if (mUpdateTargetWorkDuration && mReportActualWorkDuration) { - constexpr int64_t kSanityCheckLowerBound = 100000; // 0.1ms - constexpr int64_t kSanityCheckUpperBound = 10000000000; // 10s - int64_t targetWorkDuration = frameDeadline - intendedVsync; - targetWorkDuration = targetWorkDuration * Properties::targetCpuTimePercentage / 100; - if (targetWorkDuration > kSanityCheckLowerBound && - targetWorkDuration < kSanityCheckUpperBound && - targetWorkDuration != mLastTargetWorkDuration) { - mLastTargetWorkDuration = targetWorkDuration; - mUpdateTargetWorkDuration(targetWorkDuration); - } - int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime; - int64_t actualDuration = frameDuration - - (std::min(syncDelayDuration, mLastDequeueBufferDuration)) - - dequeueBufferDuration; - if (actualDuration > kSanityCheckLowerBound && actualDuration < kSanityCheckUpperBound) { - mReportActualWorkDuration(actualDuration); - } + if (!mHintSessionWrapper) mHintSessionWrapper.emplace(mUiThreadId, mRenderThreadId); + constexpr int64_t kSanityCheckLowerBound = 100000; // 0.1ms + constexpr int64_t kSanityCheckUpperBound = 10000000000; // 10s + int64_t targetWorkDuration = frameDeadline - intendedVsync; + targetWorkDuration = targetWorkDuration * Properties::targetCpuTimePercentage / 100; + if (targetWorkDuration > kSanityCheckLowerBound && + targetWorkDuration < kSanityCheckUpperBound && + targetWorkDuration != mLastTargetWorkDuration) { + mLastTargetWorkDuration = targetWorkDuration; + mHintSessionWrapper->updateTargetWorkDuration(targetWorkDuration); } + int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime; + int64_t actualDuration = frameDuration - + (std::min(syncDelayDuration, mLastDequeueBufferDuration)) - + dequeueBufferDuration; + if (actualDuration > kSanityCheckLowerBound && actualDuration < kSanityCheckUpperBound) { + mHintSessionWrapper->reportActualWorkDuration(actualDuration); + } + mLastDequeueBufferDuration = dequeueBufferDuration; } @@ -216,6 +263,44 @@ void DrawFrameTask::unblockUiThread() { mSignal.signal(); } +DrawFrameTask::HintSessionWrapper::HintSessionWrapper(int32_t uiThreadId, int32_t renderThreadId) { + if (!Properties::useHintManager) return; + if (uiThreadId < 0 || renderThreadId < 0) return; + + ensureAPerformanceHintBindingInitialized(); + + APerformanceHintManager* manager = gAPH_getManagerFn(); + if (!manager) return; + + std::vector tids = CommonPool::getThreadIds(); + tids.push_back(uiThreadId); + tids.push_back(renderThreadId); + + // DrawFrameTask code will always set a target duration before reporting actual durations. + // So this is just a placeholder value that's never used. + int64_t dummyTargetDurationNanos = 16666667; + mHintSession = + gAPH_createSessionFn(manager, tids.data(), tids.size(), dummyTargetDurationNanos); +} + +DrawFrameTask::HintSessionWrapper::~HintSessionWrapper() { + if (mHintSession) { + gAPH_closeSessionFn(mHintSession); + } +} + +void DrawFrameTask::HintSessionWrapper::updateTargetWorkDuration(long targetDurationNanos) { + if (mHintSession) { + gAPH_updateTargetWorkDurationFn(mHintSession, targetDurationNanos); + } +} + +void DrawFrameTask::HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) { + if (mHintSession) { + gAPH_reportActualWorkDurationFn(mHintSession, actualDurationNanos); + } +} + } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h index 2455ea84c94eb..6a61a2bb645f7 100644 --- a/libs/hwui/renderthread/DrawFrameTask.h +++ b/libs/hwui/renderthread/DrawFrameTask.h @@ -16,8 +16,10 @@ #ifndef DRAWFRAMETASK_H #define DRAWFRAMETASK_H +#include #include +#include #include #include #include @@ -60,9 +62,8 @@ public: DrawFrameTask(); virtual ~DrawFrameTask(); - void setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode); - void setHintSessionCallbacks(std::function updateTargetWorkDuration, - std::function reportActualWorkDuration); + void setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode, + int32_t uiThreadId, int32_t renderThreadId); void setContentDrawBounds(int left, int top, int right, int bottom) { mContentDrawBounds.set(left, top, right, bottom); } @@ -85,6 +86,18 @@ public: } private: + class HintSessionWrapper { + public: + HintSessionWrapper(int32_t uiThreadId, int32_t renderThreadId); + ~HintSessionWrapper(); + + void updateTargetWorkDuration(long targetDurationNanos); + void reportActualWorkDuration(long actualDurationNanos); + + private: + APerformanceHintSession* mHintSession = nullptr; + }; + void postAndWait(); bool syncFrameState(TreeInfo& info); void unblockUiThread(); @@ -95,6 +108,8 @@ private: RenderThread* mRenderThread; CanvasContext* mContext; RenderNode* mTargetNode = nullptr; + int32_t mUiThreadId = -1; + int32_t mRenderThreadId = -1; Rect mContentDrawBounds; /********************************************* @@ -112,8 +127,7 @@ private: nsecs_t mLastDequeueBufferDuration = 0; nsecs_t mLastTargetWorkDuration = 0; - std::function mUpdateTargetWorkDuration; - std::function mReportActualWorkDuration; + std::optional mHintSessionWrapper; }; } /* namespace renderthread */ diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index a77b5b5699075..c485ce2781e5a 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -29,6 +29,8 @@ #include "utils/Macros.h" #include "utils/TimeUtils.h" +#include + namespace android { namespace uirenderer { namespace renderthread { @@ -39,7 +41,8 @@ RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode, mContext = mRenderThread.queue().runSync([&]() -> CanvasContext* { return CanvasContext::create(mRenderThread, translucent, rootRenderNode, contextFactory); }); - mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode); + mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode, + pthread_gettid_np(pthread_self()), getRenderThreadTid()); } RenderProxy::~RenderProxy() { @@ -48,7 +51,7 @@ RenderProxy::~RenderProxy() { void RenderProxy::destroyContext() { if (mContext) { - mDrawFrameTask.setContext(nullptr, nullptr, nullptr); + mDrawFrameTask.setContext(nullptr, nullptr, nullptr, -1, -1); // This is also a fence as we need to be certain that there are no // outstanding mDrawFrame tasks posted before it is destroyed mRenderThread.queue().runSync([this]() { delete mContext; }); @@ -76,12 +79,6 @@ void RenderProxy::setName(const char* name) { mRenderThread.queue().runSync([this, name]() { mContext->setName(std::string(name)); }); } -void RenderProxy::setHintSessionCallbacks(std::function updateTargetWorkDuration, - std::function reportActualWorkDuration) { - mDrawFrameTask.setHintSessionCallbacks(std::move(updateTargetWorkDuration), - std::move(reportActualWorkDuration)); -} - void RenderProxy::setSurface(ANativeWindow* window, bool enableTimeout) { if (window) { ANativeWindow_acquire(window); } mRenderThread.queue().post([this, win = window, enableTimeout]() mutable { diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 1b0f22e75a2de..2b5405c82563a 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -71,8 +71,6 @@ public: void setSwapBehavior(SwapBehavior swapBehavior); bool loadSystemProperties(); void setName(const char* name); - void setHintSessionCallbacks(std::function updateTargetWorkDuration, - std::function reportActualWorkDuration); void setSurface(ANativeWindow* window, bool enableTimeout = true); void setSurfaceControl(ASurfaceControl* surfaceControl);