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

Commit 0e375753 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add support for createHintSessionWithConfig" into main

parents 4c17d771 e073c73f
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -18,16 +18,21 @@
package android.os;

import android.os.IHintSession;
import android.hardware.power.SessionConfig;
import android.hardware.power.SessionTag;

/** {@hide} */
interface IHintManager {
    /**
     * Creates a {@link Session} for the given set of threads and associates to a binder token.
     * Returns a config if creation is not supported, and HMS had to use the
     * legacy creation method.
     */
    IHintSession createHintSession(in IBinder token, in int[] tids, long durationNanos);
    IHintSession createHintSessionWithConfig(in IBinder token, in int[] threadIds,
            in long durationNanos, in SessionTag tag, out @nullable SessionConfig config);

    /**
     * Get preferred rate limit in nano second.
     * Get preferred rate limit in nanoseconds.
     */
    long getHintSessionPreferredRate();

+28 −16
Original line number Diff line number Diff line
@@ -59,7 +59,8 @@ public:
    ~APerformanceHintManager() = default;

    APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
                                           int64_t initialTargetWorkDurationNanos);
                                           int64_t initialTargetWorkDurationNanos,
                                           hal::SessionTag tag = hal::SessionTag::OTHER);
    int64_t getPreferredRateNanos() const;

private:
@@ -84,7 +85,8 @@ struct APerformanceHintSession {
public:
    APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
                            std::shared_ptr<IHintSession> session, int64_t preferredRateNanos,
                            int64_t targetDurationNanos);
                            int64_t targetDurationNanos,
                            std::optional<hal::SessionConfig> sessionConfig);
    APerformanceHintSession() = delete;
    ~APerformanceHintSession();

@@ -116,9 +118,10 @@ private:
    // Cached samples
    std::vector<hal::WorkDuration> mActualWorkDurations;
    std::string mSessionName;
    static int32_t sIDCounter;
    static int64_t sIDCounter;
    // The most recent set of thread IDs
    std::vector<int32_t> mLastThreadIDs;
    std::optional<hal::SessionConfig> mSessionConfig;
    // Tracing helpers
    void traceThreads(std::vector<int32_t>& tids);
    void tracePowerEfficient(bool powerEfficient);
@@ -129,7 +132,8 @@ private:

static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
static APerformanceHintManager* gHintManagerForTesting = nullptr;
int32_t APerformanceHintSession::sIDCounter = 0;
// Start above the int32 range so we don't collide with config sessions
int64_t APerformanceHintSession::sIDCounter = INT32_MAX;

// ===================================== APerformanceHintManager implementation
APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager> manager,
@@ -174,16 +178,20 @@ APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintMa
}

APerformanceHintSession* APerformanceHintManager::createSession(
        const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos) {
        const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos,
        hal::SessionTag tag) {
    std::vector<int32_t> tids(threadIds, threadIds + size);
    std::shared_ptr<IHintSession> session;
    ndk::ScopedAStatus ret =
            mHintManager->createHintSession(mToken, tids, initialTargetWorkDurationNanos, &session);
    ndk::ScopedAStatus ret;
    std::optional<hal::SessionConfig> sessionConfig;
    ret = mHintManager->createHintSessionWithConfig(mToken, tids, initialTargetWorkDurationNanos,
                                                    tag, &sessionConfig, &session);

    if (!ret.isOk() || !session) {
        return nullptr;
    }
    auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
                                           initialTargetWorkDurationNanos);
                                           initialTargetWorkDurationNanos, sessionConfig);
    out->traceThreads(tids);
    out->traceTargetDuration(initialTargetWorkDurationNanos);
    out->tracePowerEfficient(false);
@@ -199,19 +207,23 @@ int64_t APerformanceHintManager::getPreferredRateNanos() const {
APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
                                                 std::shared_ptr<IHintSession> session,
                                                 int64_t preferredRateNanos,
                                                 int64_t targetDurationNanos)
                                                 int64_t targetDurationNanos,
                                                 std::optional<hal::SessionConfig> sessionConfig)
      : mHintManager(hintManager),
        mHintSession(std::move(session)),
        mPreferredRateNanos(preferredRateNanos),
        mTargetDurationNanos(targetDurationNanos),
        mFirstTargetMetTimestamp(0),
        mLastTargetMetTimestamp(0) {
    const std::vector<hal::SessionHint> sessionHintRange{ndk::enum_range<hal::SessionHint>()
                                                                 .begin(),
                                                         ndk::enum_range<hal::SessionHint>().end()};

    mLastHintSentTimestamp = std::vector<int64_t>(sessionHintRange.size(), 0);
    mSessionName = android::base::StringPrintf("ADPF Session %" PRId32, ++sIDCounter);
        mLastTargetMetTimestamp(0),
        mSessionConfig(sessionConfig) {
    if (sessionConfig->id > INT32_MAX) {
        ALOGE("Session ID too large, must fit 32-bit integer");
    }
    constexpr int numEnums =
            ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin();
    mLastHintSentTimestamp = std::vector<int64_t>(numEnums, 0);
    int64_t traceId = sessionConfig.has_value() ? sessionConfig->id : ++sIDCounter;
    mSessionName = android::base::StringPrintf("ADPF Session %" PRId64, traceId);
}

APerformanceHintSession::~APerformanceHintSession() {
+21 −5
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

#define LOG_TAG "PerformanceHintNativeTest"

#include <aidl/android/hardware/power/SessionConfig.h>
#include <aidl/android/hardware/power/SessionTag.h>
#include <aidl/android/hardware/power/WorkDuration.h>
#include <aidl/android/os/IHintManager.h>
#include <android/binder_manager.h>
@@ -28,6 +30,8 @@
#include <memory>
#include <vector>

using aidl::android::hardware::power::SessionConfig;
using aidl::android::hardware::power::SessionTag;
using aidl::android::hardware::power::WorkDuration;
using aidl::android::os::IHintManager;
using aidl::android::os::IHintSession;
@@ -39,8 +43,9 @@ using namespace testing;

class MockIHintManager : public IHintManager {
public:
    MOCK_METHOD(ScopedAStatus, createHintSession,
    MOCK_METHOD(ScopedAStatus, createHintSessionWithConfig,
                (const SpAIBinder& token, const ::std::vector<int32_t>& tids, int64_t durationNanos,
                 SessionTag tag, std::optional<SessionConfig>* config,
                 std::shared_ptr<IHintSession>* _aidl_return),
                (override));
    MOCK_METHOD(ScopedAStatus, getHintSessionPreferredRate, (int64_t * _aidl_return), (override));
@@ -92,14 +97,18 @@ public:
    APerformanceHintSession* createSession(APerformanceHintManager* manager,
                                           int64_t targetDuration = 56789L) {
        mMockSession = ndk::SharedRefBase::make<NiceMock<MockIHintSession>>();

        int64_t sessionId = 123;
        std::vector<int32_t> tids;
        tids.push_back(1);
        tids.push_back(2);

        ON_CALL(*mMockIHintManager, createHintSession(_, Eq(tids), Eq(targetDuration), _))
                .WillByDefault(DoAll(SetArgPointee<3>(std::shared_ptr<IHintSession>(mMockSession)),
        ON_CALL(*mMockIHintManager,
                createHintSessionWithConfig(_, Eq(tids), Eq(targetDuration), _, _, _))
                .WillByDefault(DoAll(SetArgPointee<4>(
                                             std::make_optional<SessionConfig>({.id = sessionId})),
                                     SetArgPointee<5>(std::shared_ptr<IHintSession>(mMockSession)),
                                     [] { return ScopedAStatus::ok(); }));

        ON_CALL(*mMockIHintManager, setHintSessionThreads(_, _)).WillByDefault([] {
            return ScopedAStatus::ok();
        });
@@ -115,7 +124,6 @@ public:
        ON_CALL(*mMockSession, reportActualWorkDuration2(_)).WillByDefault([] {
            return ScopedAStatus::ok();
        });

        return APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration);
    }

@@ -178,6 +186,14 @@ TEST_F(PerformanceHintTest, TestSession) {
    APerformanceHint_closeSession(session);
}

TEST_F(PerformanceHintTest, TestUpdatedSessionCreation) {
    EXPECT_CALL(*mMockIHintManager, createHintSessionWithConfig(_, _, _, _, _, _)).Times(1);
    APerformanceHintManager* manager = createManager();
    APerformanceHintSession* session = createSession(manager);
    ASSERT_TRUE(session);
    APerformanceHint_closeSession(session);
}

TEST_F(PerformanceHintTest, SetThreads) {
    APerformanceHintManager* manager = createManager();

+51 −8
Original line number Diff line number Diff line
@@ -20,11 +20,14 @@ import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import static com.android.server.power.hint.Flags.powerhintThreadCleanup;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.StatsManager;
import android.app.UidObserver;
import android.content.Context;
import android.hardware.power.SessionConfig;
import android.hardware.power.SessionTag;
import android.hardware.power.WorkDuration;
import android.os.Binder;
import android.os.Handler;
@@ -67,6 +70,7 @@ import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/** An hint service implementation that runs in System Server process. */
public final class HintManagerService extends SystemService {
@@ -87,7 +91,7 @@ public final class HintManagerService extends SystemService {
    @GuardedBy("mLock")
    private final ArrayMap<Integer, ArrayMap<IBinder, ArraySet<AppHintSession>>> mActiveSessions;

    /** Lock to protect HAL handles and listen list. */
    /** Lock to protect mActiveSessions. */
    private final Object mLock = new Object();

    @GuardedBy("mNonIsolatedTidsLock")
@@ -104,6 +108,8 @@ public final class HintManagerService extends SystemService {

    private final Context mContext;

    private AtomicBoolean mConfigCreationSupport = new AtomicBoolean(true);

    private static final String PROPERTY_SF_ENABLE_CPU_HINT = "debug.sf.enable_adpf_cpu_hint";
    private static final String PROPERTY_HWUI_ENABLE_HINT_MANAGER = "debug.hwui.use_hint_manager";

@@ -217,6 +223,9 @@ public final class HintManagerService extends SystemService {
        private static native long nativeCreateHintSession(int tgid, int uid, int[] tids,
                long durationNanos);

        private static native long nativeCreateHintSessionWithConfig(int tgid, int uid, int[] tids,
                long durationNanos, int tag, SessionConfig config);

        private static native void nativePauseHintSession(long halPtr);

        private static native void nativeResumeHintSession(long halPtr);
@@ -253,6 +262,12 @@ public final class HintManagerService extends SystemService {
            return nativeCreateHintSession(tgid, uid, tids, durationNanos);
        }

        /** Wrapper for HintManager.nativeCreateHintSessionWithConfig */
        public long halCreateHintSessionWithConfig(
                int tgid, int uid, int[] tids, long durationNanos, int tag, SessionConfig config) {
            return nativeCreateHintSessionWithConfig(tgid, uid, tids, durationNanos, tag, config);
        }

        /** Wrapper for HintManager.nativePauseHintSession */
        public void halPauseHintSession(long halPtr) {
            nativePauseHintSession(halPtr);
@@ -612,8 +627,12 @@ public final class HintManagerService extends SystemService {
    @VisibleForTesting
    final class BinderService extends IHintManager.Stub {
        @Override
        public IHintSession createHintSession(IBinder token, int[] tids, long durationNanos) {
            if (!isHalSupported()) return null;
        public IHintSession createHintSessionWithConfig(@NonNull IBinder token,
                @NonNull int[] tids, long durationNanos, @SessionTag int tag,
                @Nullable SessionConfig config) {
            if (!isHalSupported()) {
                throw new UnsupportedOperationException("PowerHAL is not supported!");
            }

            java.util.Objects.requireNonNull(token);
            java.util.Objects.requireNonNull(tids);
@@ -634,8 +653,35 @@ public final class HintManagerService extends SystemService {
                    throw new SecurityException(errMsg);
                }

                long halSessionPtr = mNativeWrapper.halCreateHintSession(callingTgid, callingUid,
                        tids, durationNanos);
                Long halSessionPtr = null;
                if (mConfigCreationSupport.get()) {
                    try {
                        halSessionPtr = mNativeWrapper.halCreateHintSessionWithConfig(
                                callingTgid, callingUid, tids, durationNanos, tag, config);
                    } catch (UnsupportedOperationException e) {
                        mConfigCreationSupport.set(false);
                    } catch (IllegalStateException e) {
                        Slog.e("createHintSessionWithConfig failed: ", e.getMessage());
                        throw new IllegalStateException(
                            "createHintSessionWithConfig failed: " + e.getMessage());
                    }
                }

                if (halSessionPtr == null) {
                    try {
                        halSessionPtr = mNativeWrapper.halCreateHintSession(callingTgid,
                                callingUid, tids, durationNanos);
                    } catch (UnsupportedOperationException e) {
                        Slog.w("createHintSession unsupported: ", e.getMessage());
                        throw new UnsupportedOperationException(
                            "createHintSession unsupported: " + e.getMessage());
                    } catch (IllegalStateException e) {
                        Slog.e("createHintSession failed: ", e.getMessage());
                        throw new IllegalStateException(
                            "createHintSession failed: " + e.getMessage());
                    }
                }

                if (powerhintThreadCleanup()) {
                    synchronized (mNonIsolatedTidsLock) {
                        for (int i = nonIsolated.size() - 1; i >= 0; i--) {
@@ -644,9 +690,6 @@ public final class HintManagerService extends SystemService {
                        }
                    }
                }
                if (halSessionPtr == 0) {
                    return null;
                }

                AppHintSession hs = new AppHintSession(callingUid, callingTgid, tids, token,
                        halSessionPtr, durationNanos);
+63 −3
Original line number Diff line number Diff line
@@ -34,13 +34,13 @@

#include "jni.h"

using aidl::android::hardware::power::SessionConfig;
using aidl::android::hardware::power::SessionHint;
using aidl::android::hardware::power::SessionMode;
using aidl::android::hardware::power::SessionTag;
using aidl::android::hardware::power::WorkDuration;
using android::power::PowerHintSessionWrapper;

using android::base::StringPrintf;

namespace android {

static struct {
@@ -66,6 +66,15 @@ static int64_t getHintSessionPreferredRate() {
    return rate;
}

void throwUnsupported(JNIEnv* env, const char* msg) {
    env->ThrowNew(env->FindClass("java/lang/UnsupportedOperationException"), msg);
}

void throwFailed(JNIEnv* env, const char* msg) {
    // We throw IllegalStateException for all errors other than the "unsupported" ones
    env->ThrowNew(env->FindClass("java/lang/IllegalStateException"), msg);
}

static jlong createHintSession(JNIEnv* env, int32_t tgid, int32_t uid,
                               std::vector<int32_t>& threadIds, int64_t durationNanos) {
    auto result = gPowerHalController.createHintSession(tgid, uid, threadIds, durationNanos);
@@ -76,10 +85,38 @@ static jlong createHintSession(JNIEnv* env, int32_t tgid, int32_t uid,
        return res.second ? session_ptr : 0;
    } else if (result.isFailed()) {
        ALOGW("createHintSession failed with message: %s", result.errorMessage());
        throwFailed(env, result.errorMessage());
    } else if (result.isUnsupported()) {
        throwUnsupported(env, result.errorMessage());
        return -1;
    }
    return 0;
}

static jlong createHintSessionWithConfig(JNIEnv* env, int32_t tgid, int32_t uid,
                                         std::vector<int32_t> threadIds, int64_t durationNanos,
                                         int32_t sessionTag, SessionConfig& config) {
    auto result =
            gPowerHalController.createHintSessionWithConfig(tgid, uid, threadIds, durationNanos,
                                                            static_cast<SessionTag>(sessionTag),
                                                            &config);
    if (result.isOk()) {
        jlong session_ptr = reinterpret_cast<jlong>(result.value().get());
        std::scoped_lock sessionLock(gSessionMapLock);
        auto res = gSessionMap.insert({session_ptr, result.value()});
        if (!res.second) {
            throwFailed(env, "PowerHAL provided an invalid session");
            return 0;
        }
        return session_ptr;
    } else if (result.isUnsupported()) {
        throwUnsupported(env, result.errorMessage());
        return -1;
    }
    throwFailed(env, result.errorMessage());
    return 0;
}

static void pauseHintSession(JNIEnv* env, int64_t session_ptr) {
    auto appSession = reinterpret_cast<PowerHintSessionWrapper*>(session_ptr);
    appSession->pause();
@@ -136,13 +173,34 @@ static jlong nativeCreateHintSession(JNIEnv* env, jclass /* clazz */, jint tgid,
                                     jintArray tids, jlong durationNanos) {
    ScopedIntArrayRO tidArray(env, tids);
    if (nullptr == tidArray.get() || tidArray.size() == 0) {
        ALOGW("GetIntArrayElements returns nullptr.");
        ALOGW("nativeCreateHintSession: GetIntArrayElements returns nullptr.");
        return 0;
    }
    std::vector<int32_t> threadIds(tidArray.get(), tidArray.get() + tidArray.size());
    return createHintSession(env, tgid, uid, threadIds, durationNanos);
}

static jlong nativeCreateHintSessionWithConfig(JNIEnv* env, jclass /* clazz */, jint tgid, jint uid,
                                               jintArray tids, jlong durationNanos, jint sessionTag,
                                               jobject sessionConfig) {
    ScopedIntArrayRO tidArray(env, tids);
    if (nullptr == tidArray.get() || tidArray.size() == 0) {
        ALOGW("nativeCreateHintSessionWithConfig: GetIntArrayElements returns nullptr.");
        return 0;
    }
    std::vector<int32_t> threadIds(tidArray.get(), tidArray.get() + tidArray.size());
    SessionConfig config;
    jlong out = createHintSessionWithConfig(env, tgid, uid, std::move(threadIds), durationNanos,
                                            sessionTag, config);
    if (out <= 0) {
        return out;
    }
    static jclass configClass = env->FindClass("android/hardware/power/SessionConfig");
    static jfieldID fid = env->GetFieldID(configClass, "id", "J");
    env->SetLongField(sessionConfig, fid, config.id);
    return out;
}

static void nativePauseHintSession(JNIEnv* env, jclass /* clazz */, jlong session_ptr) {
    pauseHintSession(env, session_ptr);
}
@@ -215,6 +273,8 @@ static const JNINativeMethod sHintManagerServiceMethods[] = {
        {"nativeInit", "()V", (void*)nativeInit},
        {"nativeGetHintSessionPreferredRate", "()J", (void*)nativeGetHintSessionPreferredRate},
        {"nativeCreateHintSession", "(II[IJ)J", (void*)nativeCreateHintSession},
        {"nativeCreateHintSessionWithConfig", "(II[IJILandroid/hardware/power/SessionConfig;)J",
         (void*)nativeCreateHintSessionWithConfig},
        {"nativePauseHintSession", "(J)V", (void*)nativePauseHintSession},
        {"nativeResumeHintSession", "(J)V", (void*)nativeResumeHintSession},
        {"nativeCloseHintSession", "(J)V", (void*)nativeCloseHintSession},
Loading