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

Commit 9c03b50a authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Add Shared timeline jank classification listener (1/2)

Adds the ability to register a listener that gets informed about
SF' jank classifications via the TransactionCompleted interface

Bug: 17475548
Test: FrameTimelineTest
Test: Register listener, ensure data flows back
Change-Id: Ie42c508da605c03569eadab6ab18b7315b35d247
parent 5814ab8b
Loading
Loading
Loading
Loading
+46 −42
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
#define LOG_TAG "ITransactionCompletedListener"
//#define LOG_NDEBUG 0

#include <gui/LayerState.h>
#include <gui/ISurfaceComposer.h>
#include <gui/ITransactionCompletedListener.h>

namespace android {
@@ -90,61 +92,63 @@ status_t FrameEventHistoryStats::readFromParcel(const Parcel* input) {
    return err;
}

status_t SurfaceStats::writeToParcel(Parcel* output) const {
    status_t err = output->writeStrongBinder(surfaceControl);
    if (err != NO_ERROR) {
        return err;
JankData::JankData() :
        frameVsyncId(ISurfaceComposer::INVALID_VSYNC_ID),
        jankType(JankType::None) {
}
    err = output->writeInt64(acquireTime);
    if (err != NO_ERROR) {
        return err;

status_t JankData::writeToParcel(Parcel* output) const {
    SAFE_PARCEL(output->writeInt64, frameVsyncId);
    SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(jankType));
    return NO_ERROR;
}
    if (previousReleaseFence) {
        err = output->writeBool(true);
        if (err != NO_ERROR) {
            return err;

status_t JankData::readFromParcel(const Parcel* input) {
    SAFE_PARCEL(input->readInt64, &frameVsyncId);
    int32_t jankTypeInt;
    SAFE_PARCEL(input->readInt32, &jankTypeInt);
    jankType = static_cast<JankType>(jankTypeInt);
    return NO_ERROR;
}
        err = output->write(*previousReleaseFence);

status_t SurfaceStats::writeToParcel(Parcel* output) const {
    SAFE_PARCEL(output->writeStrongBinder, surfaceControl);
    SAFE_PARCEL(output->writeInt64, acquireTime);
    if (previousReleaseFence) {
        SAFE_PARCEL(output->writeBool, true);
        SAFE_PARCEL(output->write, *previousReleaseFence);
    } else {
        err = output->writeBool(false);
        SAFE_PARCEL(output->writeBool, false);
    }
    err = output->writeUint32(transformHint);
    if (err != NO_ERROR) {
        return err;
    SAFE_PARCEL(output->writeUint32, transformHint);
    SAFE_PARCEL(output->writeParcelable, eventStats);
    SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(jankData.size()));
    for (const auto& data : jankData) {
        SAFE_PARCEL(output->writeParcelable, data);
    }

    err = output->writeParcelable(eventStats);
    return err;
    return NO_ERROR;
}

status_t SurfaceStats::readFromParcel(const Parcel* input) {
    status_t err = input->readStrongBinder(&surfaceControl);
    if (err != NO_ERROR) {
        return err;
    }
    err = input->readInt64(&acquireTime);
    if (err != NO_ERROR) {
        return err;
    }
    SAFE_PARCEL(input->readStrongBinder, &surfaceControl);
    SAFE_PARCEL(input->readInt64, &acquireTime);
    bool hasFence = false;
    err = input->readBool(&hasFence);
    if (err != NO_ERROR) {
        return err;
    }
    SAFE_PARCEL(input->readBool, &hasFence);
    if (hasFence) {
        previousReleaseFence = new Fence();
        err = input->read(*previousReleaseFence);
        if (err != NO_ERROR) {
            return err;
        }
    }
    err = input->readUint32(&transformHint);
    if (err != NO_ERROR) {
        return err;
        SAFE_PARCEL(input->read, *previousReleaseFence);
    }
    SAFE_PARCEL(input->readUint32, &transformHint);
    SAFE_PARCEL(input->readParcelable, &eventStats);

    err = input->readParcelable(&eventStats);
    return err;
    int32_t jankData_size = 0;
    SAFE_PARCEL_READ_SIZE(input->readInt32, &jankData_size, input->dataSize());
    for (int i = 0; i < jankData_size; i++) {
        JankData data;
        SAFE_PARCEL(input->readParcelable, &data);
        jankData.push_back(data);
    }
    return NO_ERROR;
}

status_t TransactionStats::writeToParcel(Parcel* output) const {
+29 −0
Original line number Diff line number Diff line
@@ -125,6 +125,9 @@ sp<SurfaceComposerClient> SurfaceComposerClient::getDefault() {
    return DefaultComposerClient::getComposerClient();
}

JankDataListener::~JankDataListener() {
}

// ---------------------------------------------------------------------------

// TransactionCompletedListener does not use ANDROID_SINGLETON_STATIC_INSTANCE because it needs
@@ -174,6 +177,23 @@ CallbackId TransactionCompletedListener::addCallbackFunction(
    return callbackId;
}

void TransactionCompletedListener::addJankListener(const sp<JankDataListener>& listener,
                                                   sp<SurfaceControl> surfaceControl) {
    std::lock_guard<std::mutex> lock(mMutex);
    mJankListeners.insert({surfaceControl->getHandle(), listener});
}

void TransactionCompletedListener::removeJankListener(const sp<JankDataListener>& listener) {
    std::lock_guard<std::mutex> lock(mMutex);
    for (auto it = mJankListeners.begin(); it != mJankListeners.end();) {
        if (it->second == listener) {
            it = mJankListeners.erase(it);
        } else {
            it++;
        }
    }
}

void TransactionCompletedListener::addSurfaceControlToCallbacks(
        const sp<SurfaceControl>& surfaceControl,
        const std::unordered_set<CallbackId>& callbackIds) {
@@ -189,6 +209,7 @@ void TransactionCompletedListener::addSurfaceControlToCallbacks(

void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
    std::unordered_map<CallbackId, CallbackTranslation> callbacksMap;
    std::multimap<sp<IBinder>, sp<JankDataListener>> jankListenersMap;
    {
        std::lock_guard<std::mutex> lock(mMutex);

@@ -204,6 +225,7 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener
         * sp<SurfaceControl> that could possibly exist for the callbacks.
         */
        callbacksMap = mCallbacks;
        jankListenersMap = mJankListeners;
        for (const auto& transactionStats : listenerStats.transactionStats) {
            for (auto& callbackId : transactionStats.callbackIds) {
                mCallbacks.erase(callbackId);
@@ -236,6 +258,13 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener
            callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
                             surfaceControlStats);
        }
        for (const auto& surfaceStats : transactionStats.surfaceStats) {
            if (surfaceStats.jankData.empty()) continue;
            for (auto it = jankListenersMap.find(surfaceStats.surfaceControl);
                    it != jankListenersMap.end(); it++) {
                it->second->onJankDataAvailable(surfaceStats.jankData);
            }
        }
    }
}

+28 −2
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

#pragma once

#include "JankInfo.h"

#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
@@ -57,6 +59,27 @@ public:
    nsecs_t dequeueReadyTime;
};

/**
 * Jank information representing SurfaceFlinger's jank classification about frames for a specific
 * surface.
 */
class JankData : public Parcelable {
public:
    status_t writeToParcel(Parcel* output) const override;
    status_t readFromParcel(const Parcel* input) override;

    JankData();
    JankData(int64_t frameVsyncId, JankType jankType)
          : frameVsyncId(frameVsyncId),
            jankType(jankType) {}

    // Identifier for the frame submitted with Transaction.setFrameTimelineVsyncId
    int64_t frameVsyncId;

    // The type of jank occurred
    JankType jankType;
};

class SurfaceStats : public Parcelable {
public:
    status_t writeToParcel(Parcel* output) const override;
@@ -64,18 +87,21 @@ public:

    SurfaceStats() = default;
    SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence,
                 uint32_t hint, FrameEventHistoryStats frameEventStats)
                 uint32_t hint, FrameEventHistoryStats frameEventStats,
                 std::vector<JankData> jankData)
          : surfaceControl(sc),
            acquireTime(time),
            previousReleaseFence(prevReleaseFence),
            transformHint(hint),
            eventStats(frameEventStats) {}
            eventStats(frameEventStats),
            jankData(std::move(jankData)) {}

    sp<IBinder> surfaceControl;
    nsecs_t acquireTime = -1;
    sp<Fence> previousReleaseFence;
    uint32_t transformHint = 0;
    FrameEventHistoryStats eventStats;
    std::vector<JankData> jankData;
};

class TransactionStats : public Parcelable {
+19 −0
Original line number Diff line number Diff line
@@ -619,6 +619,12 @@ public:

// ---------------------------------------------------------------------------

class JankDataListener : public VirtualLightRefBase {
public:
    virtual ~JankDataListener() = 0;
    virtual void onJankDataAvailable(const std::vector<JankData>& jankData) = 0;
};

class TransactionCompletedListener : public BnTransactionCompletedListener {
    TransactionCompletedListener();

@@ -637,6 +643,7 @@ class TransactionCompletedListener : public BnTransactionCompletedListener {
    };

    std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex);
    std::multimap<sp<IBinder>, sp<JankDataListener>> mJankListeners GUARDED_BY(mMutex);

public:
    static sp<TransactionCompletedListener> getInstance();
@@ -652,6 +659,18 @@ public:
    void addSurfaceControlToCallbacks(const sp<SurfaceControl>& surfaceControl,
                                      const std::unordered_set<CallbackId>& callbackIds);

    /*
     * Adds a jank listener to be informed about SurfaceFlinger's jank classification for a specific
     * surface. Jank classifications arrive as part of the transaction callbacks about previous
     * frames submitted to this Surface.
     */
    void addJankListener(const sp<JankDataListener>& listener, sp<SurfaceControl> surfaceControl);

    /**
     * Removes a jank listener previously added to addJankCallback.
     */
    void removeJankListener(const sp<JankDataListener>& listener);

    // Overrides BnTransactionCompletedListener's onTransactionCompleted
    void onTransactionCompleted(ListenerStats stats) override;
};
+1 −1
Original line number Diff line number Diff line
@@ -440,7 +440,7 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
                                                                     mName, mFrameTimelineVsyncId);
        surfaceFrame->setActualQueueTime(systemTime());

        mQueueItems.push_back({item, std::move(surfaceFrame)});
        mQueueItems.push_back({item, surfaceFrame});
        mQueuedFrames++;

        // Wake up any pending callbacks
Loading