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

Commit d9b21f6f authored by Matt Buckley's avatar Matt Buckley Committed by Android (Google) Code Review
Browse files

Merge changes Icc35293f,I05ed15cd into udc-qpr-dev

* changes:
  Mitigation for mass GC deletion
  Add unit tests for HintSessionWrapper
parents c914c49c 237bb385
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -717,6 +717,7 @@ cc_test {
        "tests/unit/EglManagerTests.cpp",
        "tests/unit/EglManagerTests.cpp",
        "tests/unit/FatVectorTests.cpp",
        "tests/unit/FatVectorTests.cpp",
        "tests/unit/GraphicsStatsServiceTests.cpp",
        "tests/unit/GraphicsStatsServiceTests.cpp",
        "tests/unit/HintSessionWrapperTests.cpp",
        "tests/unit/JankTrackerTests.cpp",
        "tests/unit/JankTrackerTests.cpp",
        "tests/unit/FrameMetricsReporterTests.cpp",
        "tests/unit/FrameMetricsReporterTests.cpp",
        "tests/unit/LayerUpdateQueueTests.cpp",
        "tests/unit/LayerUpdateQueueTests.cpp",
+7 −6
Original line number Original line Diff line number Diff line
@@ -123,7 +123,7 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode*
        , mProfiler(mJankTracker.frames(), thread.timeLord().frameIntervalNanos())
        , mProfiler(mJankTracker.frames(), thread.timeLord().frameIntervalNanos())
        , mContentDrawBounds(0, 0, 0, 0)
        , mContentDrawBounds(0, 0, 0, 0)
        , mRenderPipeline(std::move(renderPipeline))
        , mRenderPipeline(std::move(renderPipeline))
        , mHintSessionWrapper(uiThreadId, renderThreadId) {
        , mHintSessionWrapper(std::make_shared<HintSessionWrapper>(uiThreadId, renderThreadId)) {
    mRenderThread.cacheManager().registerCanvasContext(this);
    mRenderThread.cacheManager().registerCanvasContext(this);
    rootRenderNode->makeRoot();
    rootRenderNode->makeRoot();
    mRenderNodes.emplace_back(rootRenderNode);
    mRenderNodes.emplace_back(rootRenderNode);
@@ -160,6 +160,7 @@ void CanvasContext::destroy() {
    destroyHardwareResources();
    destroyHardwareResources();
    mAnimationContext->destroy();
    mAnimationContext->destroy();
    mRenderThread.cacheManager().onContextStopped(this);
    mRenderThread.cacheManager().onContextStopped(this);
    mHintSessionWrapper->delayedDestroy(mRenderThread, 2_s, mHintSessionWrapper);
}
}


static void setBufferCount(ANativeWindow* window) {
static void setBufferCount(ANativeWindow* window) {
@@ -739,7 +740,7 @@ void CanvasContext::draw(bool solelyTextureViewUpdates) {
    int64_t frameDeadline = mCurrentFrameInfo->get(FrameInfoIndex::FrameDeadline);
    int64_t frameDeadline = mCurrentFrameInfo->get(FrameInfoIndex::FrameDeadline);
    int64_t dequeueBufferDuration = mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration);
    int64_t dequeueBufferDuration = mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration);


    mHintSessionWrapper.updateTargetWorkDuration(frameDeadline - intendedVsync);
    mHintSessionWrapper->updateTargetWorkDuration(frameDeadline - intendedVsync);


    if (didDraw) {
    if (didDraw) {
        int64_t frameStartTime = mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime);
        int64_t frameStartTime = mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime);
@@ -747,7 +748,7 @@ void CanvasContext::draw(bool solelyTextureViewUpdates) {
        int64_t actualDuration = frameDuration -
        int64_t actualDuration = frameDuration -
                                 (std::min(syncDelayDuration, mLastDequeueBufferDuration)) -
                                 (std::min(syncDelayDuration, mLastDequeueBufferDuration)) -
                                 dequeueBufferDuration - idleDuration;
                                 dequeueBufferDuration - idleDuration;
        mHintSessionWrapper.reportActualWorkDuration(actualDuration);
        mHintSessionWrapper->reportActualWorkDuration(actualDuration);
    }
    }


    mLastDequeueBufferDuration = dequeueBufferDuration;
    mLastDequeueBufferDuration = dequeueBufferDuration;
@@ -1081,11 +1082,11 @@ void CanvasContext::prepareSurfaceControlForWebview() {
}
}


void CanvasContext::sendLoadResetHint() {
void CanvasContext::sendLoadResetHint() {
    mHintSessionWrapper.sendLoadResetHint();
    mHintSessionWrapper->sendLoadResetHint();
}
}


void CanvasContext::sendLoadIncreaseHint() {
void CanvasContext::sendLoadIncreaseHint() {
    mHintSessionWrapper.sendLoadIncreaseHint();
    mHintSessionWrapper->sendLoadIncreaseHint();
}
}


void CanvasContext::setSyncDelayDuration(nsecs_t duration) {
void CanvasContext::setSyncDelayDuration(nsecs_t duration) {
@@ -1093,7 +1094,7 @@ void CanvasContext::setSyncDelayDuration(nsecs_t duration) {
}
}


void CanvasContext::startHintSession() {
void CanvasContext::startHintSession() {
    mHintSessionWrapper.init();
    mHintSessionWrapper->init();
}
}


bool CanvasContext::shouldDither() {
bool CanvasContext::shouldDither() {
+1 −1
Original line number Original line Diff line number Diff line
@@ -359,7 +359,7 @@ private:
    std::function<bool(int64_t, int64_t, int64_t)> mASurfaceTransactionCallback;
    std::function<bool(int64_t, int64_t, int64_t)> mASurfaceTransactionCallback;
    std::function<void()> mPrepareSurfaceControlForWebviewCallback;
    std::function<void()> mPrepareSurfaceControlForWebviewCallback;


    HintSessionWrapper mHintSessionWrapper;
    std::shared_ptr<HintSessionWrapper> mHintSessionWrapper;
    nsecs_t mLastDequeueBufferDuration = 0;
    nsecs_t mLastDequeueBufferDuration = 0;
    nsecs_t mSyncDelayDuration = 0;
    nsecs_t mSyncDelayDuration = 0;
    nsecs_t mIdleDuration = 0;
    nsecs_t mIdleDuration = 0;
+56 −65
Original line number Original line Diff line number Diff line
@@ -24,6 +24,7 @@
#include <vector>
#include <vector>


#include "../Properties.h"
#include "../Properties.h"
#include "RenderThread.h"
#include "thread/CommonPool.h"
#include "thread/CommonPool.h"


using namespace std::chrono_literals;
using namespace std::chrono_literals;
@@ -32,76 +33,42 @@ namespace android {
namespace uirenderer {
namespace uirenderer {
namespace renderthread {
namespace renderthread {


namespace {
#define BIND_APH_METHOD(name)                                         \
    name = (decltype(name))dlsym(handle_, "APerformanceHint_" #name); \
    LOG_ALWAYS_FATAL_IF(name == nullptr, "Failed to find required symbol APerformanceHint_" #name)


typedef APerformanceHintManager* (*APH_getManager)();
void HintSessionWrapper::HintSessionBinding::init() {
typedef APerformanceHintSession* (*APH_createSession)(APerformanceHintManager*, const int32_t*,
    if (mInitialized) return;
                                                      size_t, int64_t);
typedef void (*APH_closeSession)(APerformanceHintSession* session);
typedef void (*APH_updateTargetWorkDuration)(APerformanceHintSession*, int64_t);
typedef void (*APH_reportActualWorkDuration)(APerformanceHintSession*, int64_t);
typedef void (*APH_sendHint)(APerformanceHintSession* session, int32_t);

bool gAPerformanceHintBindingInitialized = false;
APH_getManager gAPH_getManagerFn = nullptr;
APH_createSession gAPH_createSessionFn = nullptr;
APH_closeSession gAPH_closeSessionFn = nullptr;
APH_updateTargetWorkDuration gAPH_updateTargetWorkDurationFn = nullptr;
APH_reportActualWorkDuration gAPH_reportActualWorkDurationFn = nullptr;
APH_sendHint gAPH_sendHintFn = nullptr;

void ensureAPerformanceHintBindingInitialized() {
    if (gAPerformanceHintBindingInitialized) return;


    void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
    void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
    LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!");
    LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!");


    gAPH_getManagerFn = (APH_getManager)dlsym(handle_, "APerformanceHint_getManager");
    BIND_APH_METHOD(getManager);
    LOG_ALWAYS_FATAL_IF(gAPH_getManagerFn == nullptr,
    BIND_APH_METHOD(createSession);
                        "Failed to find required symbol APerformanceHint_getManager!");
    BIND_APH_METHOD(closeSession);

    BIND_APH_METHOD(updateTargetWorkDuration);
    gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession");
    BIND_APH_METHOD(reportActualWorkDuration);
    LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr,
    BIND_APH_METHOD(sendHint);
                        "Failed to find required symbol APerformanceHint_createSession!");

    gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession");
    LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr,
                        "Failed to find required symbol APerformanceHint_closeSession!");

    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(
    mInitialized = true;
            handle_, "APerformanceHint_reportActualWorkDuration");
    LOG_ALWAYS_FATAL_IF(
            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!");

    gAPerformanceHintBindingInitialized = true;
}
}


}  // namespace

HintSessionWrapper::HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId)
HintSessionWrapper::HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId)
        : mUiThreadId(uiThreadId), mRenderThreadId(renderThreadId) {}
        : mUiThreadId(uiThreadId)
        , mRenderThreadId(renderThreadId)
        , mBinding(std::make_shared<HintSessionBinding>()) {}


HintSessionWrapper::~HintSessionWrapper() {
HintSessionWrapper::~HintSessionWrapper() {
    destroy();
    destroy();
}
}


void HintSessionWrapper::destroy() {
void HintSessionWrapper::destroy() {
    if (mHintSessionFuture.valid()) {
    if (mHintSessionFuture.has_value()) {
        mHintSession = mHintSessionFuture.get();
        mHintSession = mHintSessionFuture->get();
        mHintSessionFuture = std::nullopt;
    }
    }
    if (mHintSession) {
    if (mHintSession) {
        gAPH_closeSessionFn(mHintSession);
        mBinding->closeSession(mHintSession);
        mSessionValid = true;
        mSessionValid = true;
        mHintSession = nullptr;
        mHintSession = nullptr;
    }
    }
@@ -109,12 +76,12 @@ void HintSessionWrapper::destroy() {


bool HintSessionWrapper::init() {
bool HintSessionWrapper::init() {
    if (mHintSession != nullptr) return true;
    if (mHintSession != nullptr) return true;

    // If we're waiting for the session
    // If we're waiting for the session
    if (mHintSessionFuture.valid()) {
    if (mHintSessionFuture.has_value()) {
        // If the session is here
        // If the session is here
        if (mHintSessionFuture.wait_for(0s) == std::future_status::ready) {
        if (mHintSessionFuture->wait_for(0s) == std::future_status::ready) {
            mHintSession = mHintSessionFuture.get();
            mHintSession = mHintSessionFuture->get();
            mHintSessionFuture = std::nullopt;
            if (mHintSession != nullptr) {
            if (mHintSession != nullptr) {
                mSessionValid = true;
                mSessionValid = true;
                return true;
                return true;
@@ -133,9 +100,9 @@ bool HintSessionWrapper::init() {
    // Assume that if we return before the end, it broke
    // Assume that if we return before the end, it broke
    mSessionValid = false;
    mSessionValid = false;


    ensureAPerformanceHintBindingInitialized();
    mBinding->init();


    APerformanceHintManager* manager = gAPH_getManagerFn();
    APerformanceHintManager* manager = mBinding->getManager();
    if (!manager) return false;
    if (!manager) return false;


    std::vector<pid_t> tids = CommonPool::getThreadIds();
    std::vector<pid_t> tids = CommonPool::getThreadIds();
@@ -145,8 +112,9 @@ bool HintSessionWrapper::init() {
    // Use a placeholder target value to initialize,
    // Use a placeholder target value to initialize,
    // this will always be replaced elsewhere before it gets used
    // this will always be replaced elsewhere before it gets used
    int64_t defaultTargetDurationNanos = 16666667;
    int64_t defaultTargetDurationNanos = 16666667;
    mHintSessionFuture = CommonPool::async([=, tids = std::move(tids)] {
    mHintSessionFuture = CommonPool::async([=, this, tids = std::move(tids)] {
        return gAPH_createSessionFn(manager, tids.data(), tids.size(), defaultTargetDurationNanos);
        return mBinding->createSession(manager, tids.data(), tids.size(),
                                       defaultTargetDurationNanos);
    });
    });
    return false;
    return false;
}
}
@@ -158,7 +126,7 @@ void HintSessionWrapper::updateTargetWorkDuration(long targetWorkDurationNanos)
        targetWorkDurationNanos > kSanityCheckLowerBound &&
        targetWorkDurationNanos > kSanityCheckLowerBound &&
        targetWorkDurationNanos < kSanityCheckUpperBound) {
        targetWorkDurationNanos < kSanityCheckUpperBound) {
        mLastTargetWorkDuration = targetWorkDurationNanos;
        mLastTargetWorkDuration = targetWorkDurationNanos;
        gAPH_updateTargetWorkDurationFn(mHintSession, targetWorkDurationNanos);
        mBinding->updateTargetWorkDuration(mHintSession, targetWorkDurationNanos);
    }
    }
    mLastFrameNotification = systemTime();
    mLastFrameNotification = systemTime();
}
}
@@ -168,8 +136,9 @@ void HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) {
    mResetsSinceLastReport = 0;
    mResetsSinceLastReport = 0;
    if (actualDurationNanos > kSanityCheckLowerBound &&
    if (actualDurationNanos > kSanityCheckLowerBound &&
        actualDurationNanos < kSanityCheckUpperBound) {
        actualDurationNanos < kSanityCheckUpperBound) {
        gAPH_reportActualWorkDurationFn(mHintSession, actualDurationNanos);
        mBinding->reportActualWorkDuration(mHintSession, actualDurationNanos);
    }
    }
    mLastFrameNotification = systemTime();
}
}


void HintSessionWrapper::sendLoadResetHint() {
void HintSessionWrapper::sendLoadResetHint() {
@@ -179,14 +148,36 @@ void HintSessionWrapper::sendLoadResetHint() {
    if (now - mLastFrameNotification > kResetHintTimeout &&
    if (now - mLastFrameNotification > kResetHintTimeout &&
        mResetsSinceLastReport <= kMaxResetsSinceLastReport) {
        mResetsSinceLastReport <= kMaxResetsSinceLastReport) {
        ++mResetsSinceLastReport;
        ++mResetsSinceLastReport;
        gAPH_sendHintFn(mHintSession, static_cast<int>(SessionHint::CPU_LOAD_RESET));
        mBinding->sendHint(mHintSession, static_cast<int32_t>(SessionHint::CPU_LOAD_RESET));
    }
    }
    mLastFrameNotification = now;
    mLastFrameNotification = now;
}
}


void HintSessionWrapper::sendLoadIncreaseHint() {
void HintSessionWrapper::sendLoadIncreaseHint() {
    if (!init()) return;
    if (!init()) return;
    gAPH_sendHintFn(mHintSession, static_cast<int>(SessionHint::CPU_LOAD_UP));
    mBinding->sendHint(mHintSession, static_cast<int32_t>(SessionHint::CPU_LOAD_UP));
    mLastFrameNotification = systemTime();
}

bool HintSessionWrapper::alive() {
    return mHintSession != nullptr;
}

nsecs_t HintSessionWrapper::getLastUpdate() {
    return mLastFrameNotification;
}

// Requires passing in its shared_ptr since it shouldn't own a shared_ptr to itself
void HintSessionWrapper::delayedDestroy(RenderThread& rt, nsecs_t delay,
                                        std::shared_ptr<HintSessionWrapper> wrapperPtr) {
    nsecs_t lastUpdate = wrapperPtr->getLastUpdate();
    rt.queue().postDelayed(delay, [lastUpdate = lastUpdate, wrapper = wrapperPtr]() mutable {
        if (wrapper->getLastUpdate() == lastUpdate) {
            wrapper->destroy();
        }
        // Ensure the shared_ptr is killed at the end of the method
        wrapper = nullptr;
    });
}
}


} /* namespace renderthread */
} /* namespace renderthread */
+33 −1
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@
#include <android/performance_hint.h>
#include <android/performance_hint.h>


#include <future>
#include <future>
#include <optional>


#include "utils/TimeUtils.h"
#include "utils/TimeUtils.h"


@@ -27,8 +28,12 @@ namespace uirenderer {


namespace renderthread {
namespace renderthread {


class RenderThread;

class HintSessionWrapper {
class HintSessionWrapper {
public:
public:
    friend class HintSessionWrapperTests;

    HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId);
    HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId);
    ~HintSessionWrapper();
    ~HintSessionWrapper();


@@ -38,10 +43,15 @@ public:
    void sendLoadIncreaseHint();
    void sendLoadIncreaseHint();
    bool init();
    bool init();
    void destroy();
    void destroy();
    bool alive();
    nsecs_t getLastUpdate();
    void delayedDestroy(renderthread::RenderThread& rt, nsecs_t delay,
                        std::shared_ptr<HintSessionWrapper> wrapperPtr);


private:
private:
    APerformanceHintSession* mHintSession = nullptr;
    APerformanceHintSession* mHintSession = nullptr;
    std::future<APerformanceHintSession*> mHintSessionFuture;
    // This needs to work concurrently for testing
    std::optional<std::shared_future<APerformanceHintSession*>> mHintSessionFuture;


    int mResetsSinceLastReport = 0;
    int mResetsSinceLastReport = 0;
    nsecs_t mLastFrameNotification = 0;
    nsecs_t mLastFrameNotification = 0;
@@ -55,6 +65,28 @@ private:
    static constexpr nsecs_t kResetHintTimeout = 100_ms;
    static constexpr nsecs_t kResetHintTimeout = 100_ms;
    static constexpr int64_t kSanityCheckLowerBound = 100_us;
    static constexpr int64_t kSanityCheckLowerBound = 100_us;
    static constexpr int64_t kSanityCheckUpperBound = 10_s;
    static constexpr int64_t kSanityCheckUpperBound = 10_s;

    // Allows easier stub when testing
    class HintSessionBinding {
    public:
        virtual ~HintSessionBinding() = default;
        virtual void init();
        APerformanceHintManager* (*getManager)();
        APerformanceHintSession* (*createSession)(APerformanceHintManager* manager,
                                                  const int32_t* tids, size_t tidCount,
                                                  int64_t defaultTarget) = nullptr;
        void (*closeSession)(APerformanceHintSession* session) = nullptr;
        void (*updateTargetWorkDuration)(APerformanceHintSession* session,
                                         int64_t targetDuration) = nullptr;
        void (*reportActualWorkDuration)(APerformanceHintSession* session,
                                         int64_t actualDuration) = nullptr;
        void (*sendHint)(APerformanceHintSession* session, int32_t hintId) = nullptr;

    private:
        bool mInitialized = false;
    };

    std::shared_ptr<HintSessionBinding> mBinding;
};
};


} /* namespace renderthread */
} /* namespace renderthread */
Loading