Loading core/java/android/os/IHintManager.aidl +7 −2 Original line number Diff line number Diff line Loading @@ -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(); Loading native/android/performance_hint.cpp +28 −16 Original line number Diff line number Diff line Loading @@ -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: Loading @@ -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(); Loading Loading @@ -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); Loading @@ -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, Loading Loading @@ -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); Loading @@ -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() { Loading native/android/tests/performance_hint/PerformanceHintNativeTest.cpp +21 −5 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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; Loading @@ -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)); Loading Loading @@ -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(); }); Loading @@ -115,7 +124,6 @@ public: ON_CALL(*mMockSession, reportActualWorkDuration2(_)).WillByDefault([] { return ScopedAStatus::ok(); }); return APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration); } Loading Loading @@ -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(); Loading services/core/java/com/android/server/power/hint/HintManagerService.java +51 −8 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 { Loading @@ -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") Loading @@ -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"; Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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); Loading @@ -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--) { Loading @@ -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); Loading services/core/jni/com_android_server_hint_HintManagerService.cpp +63 −3 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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); Loading @@ -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(); Loading Loading @@ -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); } Loading Loading @@ -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 Loading
core/java/android/os/IHintManager.aidl +7 −2 Original line number Diff line number Diff line Loading @@ -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(); Loading
native/android/performance_hint.cpp +28 −16 Original line number Diff line number Diff line Loading @@ -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: Loading @@ -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(); Loading Loading @@ -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); Loading @@ -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, Loading Loading @@ -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); Loading @@ -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() { Loading
native/android/tests/performance_hint/PerformanceHintNativeTest.cpp +21 −5 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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; Loading @@ -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)); Loading Loading @@ -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(); }); Loading @@ -115,7 +124,6 @@ public: ON_CALL(*mMockSession, reportActualWorkDuration2(_)).WillByDefault([] { return ScopedAStatus::ok(); }); return APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration); } Loading Loading @@ -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(); Loading
services/core/java/com/android/server/power/hint/HintManagerService.java +51 −8 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 { Loading @@ -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") Loading @@ -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"; Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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); Loading @@ -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--) { Loading @@ -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); Loading
services/core/jni/com_android_server_hint_HintManagerService.cpp +63 −3 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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); Loading @@ -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(); Loading Loading @@ -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); } Loading Loading @@ -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