Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6a3fc60f authored by Bo Liu's avatar Bo Liu
Browse files

Switch HWUI to use native performance hint API

Test: None
Bug: 194204196
Change-Id: I80dfdb5d56921c465406cc4534e82738c668d46d
parent 4426772e
Loading
Loading
Loading
Loading
+0 −45
Original line number Diff line number Diff line
@@ -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();
+0 −93
Original line number Diff line number Diff line
@@ -44,8 +44,6 @@
#include <utils/StrongPointer.h>
#include <utils/Timers.h>

#include <pthread.h>

#include <algorithm>
#include <atomic>
#include <vector>
@@ -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<HintSessionWrapper> {
public:
    static sp<HintSessionWrapper> create(JNIEnv* env, RenderProxy* proxy) {
        if (!Properties::useHintManager) return nullptr;

        // Include UI thread (self), render thread, and thread pool.
        std::vector<int> 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<jint*>(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<jlong>(targetDurationNanos));
        hasExceptionAndClear(env);
    }

    void reportActualWorkDuration(long actualDurationNanos) {
        if (!mSession) return;
        JNIEnv* env = getenv(mVm);
        env->CallStaticVoidMethod(gHardwareRenderer.clazz,
                                  gHardwareRenderer.reportActualWorkDuration, mSession,
                                  static_cast<jlong>(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<RootRenderNode*>(rootRenderNodePtr);
    ContextFactoryImpl factory(rootRenderNode);
    RenderProxy* proxy = new RenderProxy(translucent, rootRenderNode, &factory);
    sp<HintSessionWrapper> 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");
+113 −28
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#include "DrawFrameTask.h"

#include <dlfcn.h>
#include <gui/TraceUtils.h>
#include <utils/Log.h>
#include <algorithm>
@@ -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<void(int64_t)> updateTargetWorkDuration,
                                            std::function<void(int64_t)> reportActualWorkDuration) {
    mUpdateTargetWorkDuration = std::move(updateTargetWorkDuration);
    mReportActualWorkDuration = std::move(reportActualWorkDuration);
    mUiThreadId = uiThreadId;
    mRenderThreadId = renderThreadId;
}

void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) {
@@ -144,9 +193,7 @@ 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) {
    if (!mHintSessionWrapper) mHintSessionWrapper.emplace(mUiThreadId, mRenderThreadId);
    constexpr int64_t kSanityCheckLowerBound = 100000;       // 0.1ms
    constexpr int64_t kSanityCheckUpperBound = 10000000000;  // 10s
    int64_t targetWorkDuration = frameDeadline - intendedVsync;
@@ -155,16 +202,16 @@ void DrawFrameTask::run() {
        targetWorkDuration < kSanityCheckUpperBound &&
        targetWorkDuration != mLastTargetWorkDuration) {
        mLastTargetWorkDuration = targetWorkDuration;
            mUpdateTargetWorkDuration(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) {
            mReportActualWorkDuration(actualDuration);
        }
        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<int32_t> 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 */
+19 −5
Original line number Diff line number Diff line
@@ -16,8 +16,10 @@
#ifndef DRAWFRAMETASK_H
#define DRAWFRAMETASK_H

#include <optional>
#include <vector>

#include <performance_hint_private.h>
#include <utils/Condition.h>
#include <utils/Mutex.h>
#include <utils/StrongPointer.h>
@@ -60,9 +62,8 @@ public:
    DrawFrameTask();
    virtual ~DrawFrameTask();

    void setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode);
    void setHintSessionCallbacks(std::function<void(int64_t)> updateTargetWorkDuration,
                                 std::function<void(int64_t)> 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<void(int64_t)> mUpdateTargetWorkDuration;
    std::function<void(int64_t)> mReportActualWorkDuration;
    std::optional<HintSessionWrapper> mHintSessionWrapper;
};

} /* namespace renderthread */
+5 −8
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@
#include "utils/Macros.h"
#include "utils/TimeUtils.h"

#include <pthread.h>

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<void(int64_t)> updateTargetWorkDuration,
                                          std::function<void(int64_t)> 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 {
Loading