Loading core/java/android/os/IHintManager.aidl +23 −11 Original line number Original line Diff line number Diff line Loading @@ -21,11 +21,13 @@ import android.os.CpuHeadroomParamsInternal; import android.os.GpuHeadroomParamsInternal; import android.os.GpuHeadroomParamsInternal; import android.os.IHintSession; import android.os.IHintSession; import android.os.SessionCreationConfig; import android.os.SessionCreationConfig; import android.hardware.power.CpuHeadroomResult; import android.hardware.power.ChannelConfig; import android.hardware.power.ChannelConfig; import android.hardware.power.CpuHeadroomResult; import android.hardware.power.GpuHeadroomResult; import android.hardware.power.GpuHeadroomResult; import android.hardware.power.SessionConfig; import android.hardware.power.SessionConfig; import android.hardware.power.SessionTag; import android.hardware.power.SessionTag; import android.hardware.power.SupportInfo; /** {@hide} */ /** {@hide} */ interface IHintManager { interface IHintManager { Loading @@ -40,11 +42,6 @@ interface IHintManager { IHintSession createHintSessionWithConfig(in IBinder token, in SessionTag tag, IHintSession createHintSessionWithConfig(in IBinder token, in SessionTag tag, in SessionCreationConfig creationConfig, out SessionConfig config); in SessionCreationConfig creationConfig, out SessionConfig config); /** * Get preferred rate limit in nanoseconds. */ long getHintSessionPreferredRate(); void setHintSessionThreads(in IHintSession hintSession, in int[] tids); void setHintSessionThreads(in IHintSession hintSession, in int[] tids); int[] getHintSessionThreadIds(in IHintSession hintSession); int[] getHintSessionThreadIds(in IHintSession hintSession); Loading @@ -60,14 +57,29 @@ interface IHintManager { @nullable GpuHeadroomResult getGpuHeadroom(in GpuHeadroomParamsInternal params); @nullable GpuHeadroomResult getGpuHeadroom(in GpuHeadroomParamsInternal params); long getGpuHeadroomMinIntervalMillis(); long getGpuHeadroomMinIntervalMillis(); /** * Get Maximum number of graphics pipeline threads allowed per-app. */ int getMaxGraphicsPipelineThreadsCount(); /** /** * Used by the JNI to pass an interface to the SessionManager; * Used by the JNI to pass an interface to the SessionManager; * for internal use only. * for internal use only. */ */ oneway void passSessionManagerBinder(in IBinder sessionManager); oneway void passSessionManagerBinder(in IBinder sessionManager); parcelable HintManagerClientData { int powerHalVersion; int maxGraphicsPipelineThreads; long preferredRateNanos; SupportInfo supportInfo; } interface IHintManagerClient { /** * Returns FMQ channel information for the caller, which it associates to the callback binder lifespan. */ oneway void receiveChannelConfig(in ChannelConfig config); } /** * Set up an ADPF client, receiving a remote client binder interface and * passing back a bundle of support and configuration information. */ HintManagerClientData registerClient(in IHintManagerClient client); } } native/android/performance_hint.cpp +72 −42 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <aidl/android/hardware/power/SessionHint.h> #include <aidl/android/hardware/power/SessionHint.h> #include <aidl/android/hardware/power/SessionMode.h> #include <aidl/android/hardware/power/SessionMode.h> #include <aidl/android/hardware/power/SessionTag.h> #include <aidl/android/hardware/power/SessionTag.h> #include <aidl/android/hardware/power/SupportInfo.h> #include <aidl/android/hardware/power/WorkDuration.h> #include <aidl/android/hardware/power/WorkDuration.h> #include <aidl/android/hardware/power/WorkDurationFixedV1.h> #include <aidl/android/hardware/power/WorkDurationFixedV1.h> #include <aidl/android/os/IHintManager.h> #include <aidl/android/os/IHintManager.h> Loading Loading @@ -148,10 +149,36 @@ private: std::future<bool> mChannelCreationFinished; std::future<bool> mChannelCreationFinished; }; }; class SupportInfoWrapper { public: SupportInfoWrapper(hal::SupportInfo& info); bool isSessionModeSupported(hal::SessionMode mode); bool isSessionHintSupported(hal::SessionHint hint); private: template <class T> bool getEnumSupportFromBitfield(T& enumValue, int64_t& supportBitfield) { // extract the bit corresponding to the enum by shifting the bitfield // over that much and cutting off any extra values return (supportBitfield >> static_cast<int>(enumValue)) % 2; } hal::SupportInfo mSupportInfo; }; class HintManagerClient : public IHintManager::BnHintManagerClient { public: // Currently a no-op that exists for FMQ init to call in the future ndk::ScopedAStatus receiveChannelConfig(const hal::ChannelConfig&) { return ndk::ScopedAStatus::ok(); } }; struct APerformanceHintManager { struct APerformanceHintManager { public: public: static APerformanceHintManager* getInstance(); static APerformanceHintManager* getInstance(); APerformanceHintManager(std::shared_ptr<IHintManager>& service, int64_t preferredRateNanos); APerformanceHintManager(std::shared_ptr<IHintManager>& service, IHintManager::HintManagerClientData&& clientData, std::shared_ptr<HintManagerClient> callbackClient); APerformanceHintManager() = delete; APerformanceHintManager() = delete; ~APerformanceHintManager(); ~APerformanceHintManager(); Loading @@ -169,29 +196,21 @@ public: FMQWrapper& getFMQWrapper(); FMQWrapper& getFMQWrapper(); bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex); bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex); void initJava(JNIEnv* _Nonnull env); void initJava(JNIEnv* _Nonnull env); ndk::ScopedAIBinder_Weak x; template <class T> template <class T> static void layersFromNativeSurfaces(ANativeWindow** windows, int numWindows, static void layersFromNativeSurfaces(ANativeWindow** windows, int numWindows, ASurfaceControl** controls, int numSurfaceControls, ASurfaceControl** controls, int numSurfaceControls, std::vector<T>& out); std::vector<T>& out); ndk::SpAIBinder& getToken(); SupportInfoWrapper& getSupportInfo(); private: private: // Necessary to create an empty binder object static void* tokenStubOnCreate(void*) { return nullptr; } static void tokenStubOnDestroy(void*) {} static binder_status_t tokenStubOnTransact(AIBinder*, transaction_code_t, const AParcel*, AParcel*) { return STATUS_OK; } static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager); static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager); std::shared_ptr<IHintManager> mHintManager; std::shared_ptr<IHintManager> mHintManager; std::shared_ptr<HintManagerClient> mCallbackClient; IHintManager::HintManagerClientData mClientData; SupportInfoWrapper mSupportInfoWrapper; ndk::SpAIBinder mToken; ndk::SpAIBinder mToken; const int64_t mPreferredRateNanos; std::optional<int32_t> mMaxGraphicsPipelineThreadsCount; FMQWrapper mFMQWrapper; FMQWrapper mFMQWrapper; double mHintBudget = kMaxLoadHintsPerInterval; double mHintBudget = kMaxLoadHintsPerInterval; int64_t mLastBudgetReplenish = 0; int64_t mLastBudgetReplenish = 0; Loading Loading @@ -273,14 +292,27 @@ static FMQWrapper& getFMQ() { return APerformanceHintManager::getInstance()->getFMQWrapper(); return APerformanceHintManager::getInstance()->getFMQWrapper(); } } // ===================================== SupportInfoWrapper implementation SupportInfoWrapper::SupportInfoWrapper(hal::SupportInfo& info) : mSupportInfo(info) {} bool SupportInfoWrapper::isSessionHintSupported(hal::SessionHint hint) { return getEnumSupportFromBitfield(hint, mSupportInfo.sessionHints); } bool SupportInfoWrapper::isSessionModeSupported(hal::SessionMode mode) { return getEnumSupportFromBitfield(mode, mSupportInfo.sessionModes); } // ===================================== APerformanceHintManager implementation // ===================================== APerformanceHintManager implementation APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager>& manager, APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager>& manager, int64_t preferredRateNanos) IHintManager::HintManagerClientData&& clientData, : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) { std::shared_ptr<HintManagerClient> callbackClient) static AIBinder_Class* tokenBinderClass = : mHintManager(std::move(manager)), AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy, mCallbackClient(callbackClient), tokenStubOnTransact); mClientData(clientData), mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr)); mSupportInfoWrapper(clientData.supportInfo), mToken(callbackClient->asBinder()) { if (mFMQWrapper.isSupported()) { if (mFMQWrapper.isSupported()) { mFMQWrapper.setToken(mToken); mFMQWrapper.setToken(mToken); mFMQWrapper.startChannel(mHintManager.get()); mFMQWrapper.startChannel(mHintManager.get()); Loading Loading @@ -315,16 +347,17 @@ APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintMa ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__); ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__); return nullptr; return nullptr; } } int64_t preferredRateNanos = -1L; std::shared_ptr<HintManagerClient> client = ndk::SharedRefBase::make<HintManagerClient>(); ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos); IHintManager::HintManagerClientData clientData; ndk::ScopedAStatus ret = manager->registerClient(client, &clientData); if (!ret.isOk()) { if (!ret.isOk()) { ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage()); ALOGE("%s: PerformanceHint is not supported. %s", __FUNCTION__, ret.getMessage()); return nullptr; return nullptr; } } if (preferredRateNanos <= 0) { if (clientData.preferredRateNanos <= 0) { preferredRateNanos = -1L; clientData.preferredRateNanos = -1L; } } return new APerformanceHintManager(manager, preferredRateNanos); return new APerformanceHintManager(manager, std::move(clientData), client); } } bool APerformanceHintManager::canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) { bool APerformanceHintManager::canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) { Loading Loading @@ -389,7 +422,9 @@ APerformanceHintSession* APerformanceHintManager::createSessionUsingConfig( ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage()); ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage()); return nullptr; return nullptr; } } auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos, auto out = new APerformanceHintSession(mHintManager, std::move(session), mClientData.preferredRateNanos, sessionCreationConfig->targetWorkDurationNanos, isJava, sessionCreationConfig->targetWorkDurationNanos, isJava, sessionConfig.id == -1 sessionConfig.id == -1 ? std::nullopt ? std::nullopt Loading @@ -416,24 +451,11 @@ APerformanceHintSession* APerformanceHintManager::getSessionFromJava(JNIEnv* env } } int64_t APerformanceHintManager::getPreferredRateNanos() const { int64_t APerformanceHintManager::getPreferredRateNanos() const { return mPreferredRateNanos; return mClientData.preferredRateNanos; } } int32_t APerformanceHintManager::getMaxGraphicsPipelineThreadsCount() { int32_t APerformanceHintManager::getMaxGraphicsPipelineThreadsCount() { if (!mMaxGraphicsPipelineThreadsCount.has_value()) { return mClientData.maxGraphicsPipelineThreads; int32_t threadsCount = -1; ndk::ScopedAStatus ret = mHintManager->getMaxGraphicsPipelineThreadsCount(&threadsCount); if (!ret.isOk()) { ALOGE("%s: PerformanceHint cannot get max graphics pipeline threads count. %s", __FUNCTION__, ret.getMessage()); return -1; } if (threadsCount <= 0) { threadsCount = -1; } mMaxGraphicsPipelineThreadsCount.emplace(threadsCount); } return mMaxGraphicsPipelineThreadsCount.value(); } } FMQWrapper& APerformanceHintManager::getFMQWrapper() { FMQWrapper& APerformanceHintManager::getFMQWrapper() { Loading @@ -450,6 +472,14 @@ void APerformanceHintManager::initJava(JNIEnv* _Nonnull env) { mJavaInitialized = true; mJavaInitialized = true; } } ndk::SpAIBinder& APerformanceHintManager::getToken() { return mToken; } SupportInfoWrapper& APerformanceHintManager::getSupportInfo() { return mSupportInfoWrapper; } // ===================================== APerformanceHintSession implementation // ===================================== APerformanceHintSession implementation constexpr int kNumEnums = enum_size<hal::SessionHint>(); constexpr int kNumEnums = enum_size<hal::SessionHint>(); Loading native/android/tests/performance_hint/PerformanceHintNativeTest.cpp +22 −13 Original line number Original line Diff line number Diff line Loading @@ -56,9 +56,6 @@ public: const SessionCreationConfig& creationConfig, hal::SessionConfig* config, const SessionCreationConfig& creationConfig, hal::SessionConfig* config, std::shared_ptr<IHintSession>* _aidl_return), std::shared_ptr<IHintSession>* _aidl_return), (override)); (override)); MOCK_METHOD(ScopedAStatus, getHintSessionPreferredRate, (int64_t * _aidl_return), (override)); MOCK_METHOD(ScopedAStatus, getMaxGraphicsPipelineThreadsCount, (int32_t* _aidl_return), (override)); MOCK_METHOD(ScopedAStatus, setHintSessionThreads, MOCK_METHOD(ScopedAStatus, setHintSessionThreads, (const std::shared_ptr<IHintSession>& hintSession, (const std::shared_ptr<IHintSession>& hintSession, const ::std::vector<int32_t>& tids), const ::std::vector<int32_t>& tids), Loading @@ -84,6 +81,11 @@ public: MOCK_METHOD(ScopedAStatus, getGpuHeadroomMinIntervalMillis, (int64_t* _aidl_return), MOCK_METHOD(ScopedAStatus, getGpuHeadroomMinIntervalMillis, (int64_t* _aidl_return), (override)); (override)); MOCK_METHOD(ScopedAStatus, passSessionManagerBinder, (const SpAIBinder& sessionManager)); MOCK_METHOD(ScopedAStatus, passSessionManagerBinder, (const SpAIBinder& sessionManager)); MOCK_METHOD(ScopedAStatus, registerClient, (const std::shared_ptr<::aidl::android::os::IHintManager::IHintManagerClient>& clientDataIn, ::aidl::android::os::IHintManager::HintManagerClientData* _aidl_return), (override)); MOCK_METHOD(SpAIBinder, asBinder, (), (override)); MOCK_METHOD(SpAIBinder, asBinder, (), (override)); MOCK_METHOD(bool, isRemote, (), (override)); MOCK_METHOD(bool, isRemote, (), (override)); }; }; Loading Loading @@ -125,10 +127,9 @@ public: APerformanceHintManager* createManager() { APerformanceHintManager* createManager() { APerformanceHint_setUseFMQForTesting(mUsingFMQ); APerformanceHint_setUseFMQForTesting(mUsingFMQ); ON_CALL(*mMockIHintManager, getHintSessionPreferredRate(_)) ON_CALL(*mMockIHintManager, registerClient(_, _)) .WillByDefault(DoAll(SetArgPointee<0>(123L), [] { return ScopedAStatus::ok(); })); .WillByDefault( ON_CALL(*mMockIHintManager, getMaxGraphicsPipelineThreadsCount(_)) DoAll(SetArgPointee<1>(mClientData), [] { return ScopedAStatus::ok(); })); .WillByDefault(DoAll(SetArgPointee<0>(5), [] { return ScopedAStatus::ok(); })); return APerformanceHint_getManager(); return APerformanceHint_getManager(); } } Loading Loading @@ -238,6 +239,20 @@ public: int kMockQueueSize = 20; int kMockQueueSize = 20; bool mUsingFMQ = false; bool mUsingFMQ = false; IHintManager::HintManagerClientData mClientData{ .powerHalVersion = 6, .maxGraphicsPipelineThreads = 5, .preferredRateNanos = 123L, .supportInfo{ .usesSessions = true, .boosts = 0, .modes = 0, .sessionHints = -1, .sessionModes = -1, .sessionTags = -1, }, }; int32_t mMaxLoadHintsPerInterval; int32_t mMaxLoadHintsPerInterval; int64_t mLoadHintInterval; int64_t mLoadHintInterval; Loading @@ -256,12 +271,6 @@ bool equalsWithoutTimestamp(hal::WorkDuration lhs, hal::WorkDuration rhs) { lhs.gpuDurationNanos == rhs.gpuDurationNanos && lhs.durationNanos == rhs.durationNanos; lhs.gpuDurationNanos == rhs.gpuDurationNanos && lhs.durationNanos == rhs.durationNanos; } } TEST_F(PerformanceHintTest, TestGetPreferredUpdateRateNanos) { APerformanceHintManager* manager = createManager(); int64_t preferredUpdateRateNanos = APerformanceHint_getPreferredUpdateRateNanos(manager); EXPECT_EQ(123L, preferredUpdateRateNanos); } TEST_F(PerformanceHintTest, TestSession) { TEST_F(PerformanceHintTest, TestSession) { APerformanceHintManager* manager = createManager(); APerformanceHintManager* manager = createManager(); APerformanceHintSession* session = createSession(manager); APerformanceHintSession* session = createSession(manager); Loading services/core/java/com/android/server/power/hint/HintManagerService.java +49 −10 Original line number Original line Diff line number Diff line Loading @@ -296,7 +296,11 @@ public final class HintManagerService extends SystemService { mPowerHalVersion = 0; mPowerHalVersion = 0; mUsesFmq = false; mUsesFmq = false; if (mPowerHal != null) { if (mPowerHal != null) { try { mSupportInfo = getSupportInfo(); mSupportInfo = getSupportInfo(); } catch (RemoteException e) { throw new IllegalStateException("Could not contact PowerHAL!", e); } } } mDefaultCpuHeadroomCalculationWindowMillis = mDefaultCpuHeadroomCalculationWindowMillis = new CpuHeadroomParamsInternal().calculationWindowMillis; new CpuHeadroomParamsInternal().calculationWindowMillis; Loading @@ -314,7 +318,7 @@ public final class HintManagerService extends SystemService { } } } } SupportInfo getSupportInfo() { SupportInfo getSupportInfo() throws RemoteException { try { try { mPowerHalVersion = mPowerHal.getInterfaceVersion(); mPowerHalVersion = mPowerHal.getInterfaceVersion(); if (mPowerHalVersion >= 6) { if (mPowerHalVersion >= 6) { Loading @@ -325,9 +329,40 @@ public final class HintManagerService extends SystemService { } } SupportInfo supportInfo = new SupportInfo(); SupportInfo supportInfo = new SupportInfo(); supportInfo.usesSessions = isHintSessionSupported(); // Global boosts & modes aren't currently relevant for HMS clients supportInfo.boosts = 0; supportInfo.modes = 0; supportInfo.sessionHints = 0; supportInfo.sessionModes = 0; supportInfo.sessionTags = 0; supportInfo.headroom = new SupportInfo.HeadroomSupportInfo(); supportInfo.headroom = new SupportInfo.HeadroomSupportInfo(); supportInfo.headroom.isCpuSupported = false; supportInfo.headroom.isCpuSupported = false; supportInfo.headroom.isGpuSupported = false; supportInfo.headroom.isGpuSupported = false; if (isHintSessionSupported()) { if (mPowerHalVersion == 4) { // Assume we support the V4 hints & modes unless specified // otherwise; this is to avoid breaking backwards compat // since we historically just assumed they were. supportInfo.sessionHints = 31; // first 5 bits are ones } if (mPowerHalVersion == 5) { // Assume we support the V5 hints & modes unless specified // otherwise; this is to avoid breaking backwards compat // since we historically just assumed they were. // Hal V5 has 8 modes, all of which it assumes are supported, // so we represent that by having the first 8 bits set supportInfo.sessionHints = 255; // first 8 bits are ones // Hal V5 has 1 mode which it assumes is supported, so we // represent that by having the first bit set supportInfo.sessionModes = 1; // Hal V5 has 5 tags, all of which it assumes are supported, // so we represent that by having the first 5 bits set supportInfo.sessionTags = 31; } } return supportInfo; return supportInfo; } } Loading Loading @@ -1228,7 +1263,7 @@ public final class HintManagerService extends SystemService { @SessionTag int tag, SessionCreationConfig creationConfig, @SessionTag int tag, SessionCreationConfig creationConfig, SessionConfig config) { SessionConfig config) { if (!isHintSessionSupported()) { if (!isHintSessionSupported()) { throw new UnsupportedOperationException("PowerHAL is not supported!"); throw new UnsupportedOperationException("PowerHintSessions are not supported!"); } } java.util.Objects.requireNonNull(token); java.util.Objects.requireNonNull(token); Loading Loading @@ -1424,12 +1459,6 @@ public final class HintManagerService extends SystemService { removeChannelItem(callingTgid, callingUid); removeChannelItem(callingTgid, callingUid); }; }; @Override public long getHintSessionPreferredRate() { return mHintSessionPreferredRate; } @Override public int getMaxGraphicsPipelineThreadsCount() { public int getMaxGraphicsPipelineThreadsCount() { return MAX_GRAPHICS_PIPELINE_THREADS_COUNT; return MAX_GRAPHICS_PIPELINE_THREADS_COUNT; } } Loading Loading @@ -1561,6 +1590,16 @@ public final class HintManagerService extends SystemService { mSessionManager = ISessionManager.Stub.asInterface(sessionManager); mSessionManager = ISessionManager.Stub.asInterface(sessionManager); } } public IHintManager.HintManagerClientData registerClient(@NonNull IHintManager.IHintManagerClient clientBinder) { IHintManager.HintManagerClientData out = new IHintManager.HintManagerClientData(); out.preferredRateNanos = mHintSessionPreferredRate; out.maxGraphicsPipelineThreads = getMaxGraphicsPipelineThreadsCount(); out.powerHalVersion = mPowerHalVersion; out.supportInfo = mSupportInfo; return out; } @Override @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) { if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) { Loading @@ -1568,7 +1607,7 @@ public final class HintManagerService extends SystemService { } } pw.println("HintSessionPreferredRate: " + mHintSessionPreferredRate); pw.println("HintSessionPreferredRate: " + mHintSessionPreferredRate); pw.println("MaxGraphicsPipelineThreadsCount: " + MAX_GRAPHICS_PIPELINE_THREADS_COUNT); pw.println("MaxGraphicsPipelineThreadsCount: " + MAX_GRAPHICS_PIPELINE_THREADS_COUNT); pw.println("HAL Support: " + isHintSessionSupported()); pw.println("Hint Session Support: " + isHintSessionSupported()); pw.println("Active Sessions:"); pw.println("Active Sessions:"); synchronized (mLock) { synchronized (mLock) { for (int i = 0; i < mActiveSessions.size(); i++) { for (int i = 0; i < mActiveSessions.size(); i++) { Loading services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java +90 −8 Original line number Original line Diff line number Diff line Loading @@ -64,6 +64,7 @@ import android.os.Binder; import android.os.CpuHeadroomParamsInternal; import android.os.CpuHeadroomParamsInternal; import android.os.GpuHeadroomParamsInternal; import android.os.GpuHeadroomParamsInternal; import android.os.IBinder; import android.os.IBinder; import android.os.IHintManager; import android.os.IHintSession; import android.os.IHintSession; import android.os.PerformanceHintManager; import android.os.PerformanceHintManager; import android.os.Process; import android.os.Process; Loading Loading @@ -154,6 +155,8 @@ public class HintManagerServiceTest { private ActivityManagerInternal mAmInternalMock; private ActivityManagerInternal mAmInternalMock; @Mock @Mock private PackageManager mMockPackageManager; private PackageManager mMockPackageManager; @Mock private IHintManager.IHintManagerClient mClientCallback; @Rule @Rule public final CheckFlagsRule mCheckFlagsRule = public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); DeviceFlagsValueProvider.createCheckFlagsRule(); Loading @@ -171,6 +174,23 @@ public class HintManagerServiceTest { }; }; } } private SupportInfo makeDefaultSupportInfo() { mSupportInfo = new SupportInfo(); mSupportInfo.usesSessions = true; // By default, mark everything as fully supported mSupportInfo.sessionHints = -1; mSupportInfo.sessionModes = -1; mSupportInfo.modes = -1; mSupportInfo.boosts = -1; mSupportInfo.sessionTags = -1; mSupportInfo.headroom = new SupportInfo.HeadroomSupportInfo(); mSupportInfo.headroom.isCpuSupported = true; mSupportInfo.headroom.cpuMinIntervalMillis = 2000; mSupportInfo.headroom.isGpuSupported = true; mSupportInfo.headroom.gpuMinIntervalMillis = 2000; return mSupportInfo; } @Before @Before public void setUp() throws Exception { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this); Loading @@ -181,12 +201,7 @@ public class HintManagerServiceTest { mConfig.eventFlagDescriptor = new MQDescriptor<Byte, Byte>(); mConfig.eventFlagDescriptor = new MQDescriptor<Byte, Byte>(); ApplicationInfo applicationInfo = new ApplicationInfo(); ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.category = ApplicationInfo.CATEGORY_GAME; applicationInfo.category = ApplicationInfo.CATEGORY_GAME; mSupportInfo = new SupportInfo(); mSupportInfo = makeDefaultSupportInfo(); mSupportInfo.headroom = new SupportInfo.HeadroomSupportInfo(); mSupportInfo.headroom.isCpuSupported = true; mSupportInfo.headroom.cpuMinIntervalMillis = 2000; mSupportInfo.headroom.isGpuSupported = true; mSupportInfo.headroom.gpuMinIntervalMillis = 2000; when(mContext.getPackageManager()).thenReturn(mMockPackageManager); when(mContext.getPackageManager()).thenReturn(mMockPackageManager); when(mMockPackageManager.getNameForUid(anyInt())).thenReturn(TEST_APP_NAME); when(mMockPackageManager.getNameForUid(anyInt())).thenReturn(TEST_APP_NAME); when(mMockPackageManager.getApplicationInfo(eq(TEST_APP_NAME), anyInt())) when(mMockPackageManager.getApplicationInfo(eq(TEST_APP_NAME), anyInt())) Loading Loading @@ -215,6 +230,7 @@ public class HintManagerServiceTest { when(mIPowerMock.getInterfaceVersion()).thenReturn(6); when(mIPowerMock.getInterfaceVersion()).thenReturn(6); when(mIPowerMock.getSupportInfo()).thenReturn(mSupportInfo); when(mIPowerMock.getSupportInfo()).thenReturn(mSupportInfo); when(mIPowerMock.getSessionChannel(anyInt(), anyInt())).thenReturn(mConfig); when(mIPowerMock.getSessionChannel(anyInt(), anyInt())).thenReturn(mConfig); when(mIPowerMock.getSupportInfo()).thenReturn(mSupportInfo); LocalServices.removeServiceForTest(ActivityManagerInternal.class); LocalServices.removeServiceForTest(ActivityManagerInternal.class); LocalServices.addService(ActivityManagerInternal.class, mAmInternalMock); LocalServices.addService(ActivityManagerInternal.class, mAmInternalMock); } } Loading Loading @@ -409,8 +425,11 @@ public class HintManagerServiceTest { HintManagerService service = createService(); HintManagerService service = createService(); IBinder token = new Binder(); IBinder token = new Binder(); final int threadCount = IHintManager.HintManagerClientData data = service.getBinderServiceInstance() service.getBinderServiceInstance().getMaxGraphicsPipelineThreadsCount(); .registerClient(mClientCallback); final int threadCount = data.maxGraphicsPipelineThreads; long sessionPtr1 = 1111L; long sessionPtr1 = 1111L; long sessionId1 = 11111L; long sessionId1 = 11111L; CountDownLatch stopLatch1 = new CountDownLatch(1); CountDownLatch stopLatch1 = new CountDownLatch(1); Loading Loading @@ -1400,4 +1419,67 @@ public class HintManagerServiceTest { verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams1)); verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams1)); verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2)); verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2)); } } @Test public void testRegisteringClient() throws Exception { HintManagerService service = createService(); IHintManager.HintManagerClientData data = service.getBinderServiceInstance() .registerClient(mClientCallback); assertNotNull(data); assertEquals(data.supportInfo, mSupportInfo); } @Test public void testRegisteringClientOnV4() throws Exception { when(mIPowerMock.getInterfaceVersion()).thenReturn(4); HintManagerService service = createService(); IHintManager.HintManagerClientData data = service.getBinderServiceInstance() .registerClient(mClientCallback); assertNotNull(data); assertEquals(data.supportInfo.usesSessions, true); assertEquals(data.supportInfo.boosts, 0); assertEquals(data.supportInfo.modes, 0); assertEquals(data.supportInfo.sessionHints, 31); assertEquals(data.supportInfo.sessionModes, 0); assertEquals(data.supportInfo.sessionTags, 0); assertEquals(data.powerHalVersion, 4); assertEquals(data.preferredRateNanos, DEFAULT_HINT_PREFERRED_RATE); } @Test public void testRegisteringClientOnV5() throws Exception { when(mIPowerMock.getInterfaceVersion()).thenReturn(5); HintManagerService service = createService(); IHintManager.HintManagerClientData data = service.getBinderServiceInstance() .registerClient(mClientCallback); assertNotNull(data); assertEquals(data.supportInfo.usesSessions, true); assertEquals(data.supportInfo.boosts, 0); assertEquals(data.supportInfo.modes, 0); assertEquals(data.supportInfo.sessionHints, 255); assertEquals(data.supportInfo.sessionModes, 1); assertEquals(data.supportInfo.sessionTags, 31); assertEquals(data.powerHalVersion, 5); assertEquals(data.preferredRateNanos, DEFAULT_HINT_PREFERRED_RATE); } @Test public void testSettingUpOldClientWhenUnsupported() throws Exception { when(mIPowerMock.getInterfaceVersion()).thenReturn(5); // Mock unsupported to modify the default support behavior when(mNativeWrapperMock.halGetHintSessionPreferredRate()) .thenReturn(-1L); HintManagerService service = createService(); IHintManager.HintManagerClientData data = service.getBinderServiceInstance() .registerClient(mClientCallback); assertNotNull(data); assertEquals(data.supportInfo.usesSessions, false); assertEquals(data.supportInfo.boosts, 0); assertEquals(data.supportInfo.modes, 0); assertEquals(data.supportInfo.sessionHints, 0); assertEquals(data.supportInfo.sessionModes, 0); assertEquals(data.supportInfo.sessionTags, 0); assertEquals(data.powerHalVersion, 5); assertEquals(data.preferredRateNanos, -1); } } } Loading
core/java/android/os/IHintManager.aidl +23 −11 Original line number Original line Diff line number Diff line Loading @@ -21,11 +21,13 @@ import android.os.CpuHeadroomParamsInternal; import android.os.GpuHeadroomParamsInternal; import android.os.GpuHeadroomParamsInternal; import android.os.IHintSession; import android.os.IHintSession; import android.os.SessionCreationConfig; import android.os.SessionCreationConfig; import android.hardware.power.CpuHeadroomResult; import android.hardware.power.ChannelConfig; import android.hardware.power.ChannelConfig; import android.hardware.power.CpuHeadroomResult; import android.hardware.power.GpuHeadroomResult; import android.hardware.power.GpuHeadroomResult; import android.hardware.power.SessionConfig; import android.hardware.power.SessionConfig; import android.hardware.power.SessionTag; import android.hardware.power.SessionTag; import android.hardware.power.SupportInfo; /** {@hide} */ /** {@hide} */ interface IHintManager { interface IHintManager { Loading @@ -40,11 +42,6 @@ interface IHintManager { IHintSession createHintSessionWithConfig(in IBinder token, in SessionTag tag, IHintSession createHintSessionWithConfig(in IBinder token, in SessionTag tag, in SessionCreationConfig creationConfig, out SessionConfig config); in SessionCreationConfig creationConfig, out SessionConfig config); /** * Get preferred rate limit in nanoseconds. */ long getHintSessionPreferredRate(); void setHintSessionThreads(in IHintSession hintSession, in int[] tids); void setHintSessionThreads(in IHintSession hintSession, in int[] tids); int[] getHintSessionThreadIds(in IHintSession hintSession); int[] getHintSessionThreadIds(in IHintSession hintSession); Loading @@ -60,14 +57,29 @@ interface IHintManager { @nullable GpuHeadroomResult getGpuHeadroom(in GpuHeadroomParamsInternal params); @nullable GpuHeadroomResult getGpuHeadroom(in GpuHeadroomParamsInternal params); long getGpuHeadroomMinIntervalMillis(); long getGpuHeadroomMinIntervalMillis(); /** * Get Maximum number of graphics pipeline threads allowed per-app. */ int getMaxGraphicsPipelineThreadsCount(); /** /** * Used by the JNI to pass an interface to the SessionManager; * Used by the JNI to pass an interface to the SessionManager; * for internal use only. * for internal use only. */ */ oneway void passSessionManagerBinder(in IBinder sessionManager); oneway void passSessionManagerBinder(in IBinder sessionManager); parcelable HintManagerClientData { int powerHalVersion; int maxGraphicsPipelineThreads; long preferredRateNanos; SupportInfo supportInfo; } interface IHintManagerClient { /** * Returns FMQ channel information for the caller, which it associates to the callback binder lifespan. */ oneway void receiveChannelConfig(in ChannelConfig config); } /** * Set up an ADPF client, receiving a remote client binder interface and * passing back a bundle of support and configuration information. */ HintManagerClientData registerClient(in IHintManagerClient client); } }
native/android/performance_hint.cpp +72 −42 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <aidl/android/hardware/power/SessionHint.h> #include <aidl/android/hardware/power/SessionHint.h> #include <aidl/android/hardware/power/SessionMode.h> #include <aidl/android/hardware/power/SessionMode.h> #include <aidl/android/hardware/power/SessionTag.h> #include <aidl/android/hardware/power/SessionTag.h> #include <aidl/android/hardware/power/SupportInfo.h> #include <aidl/android/hardware/power/WorkDuration.h> #include <aidl/android/hardware/power/WorkDuration.h> #include <aidl/android/hardware/power/WorkDurationFixedV1.h> #include <aidl/android/hardware/power/WorkDurationFixedV1.h> #include <aidl/android/os/IHintManager.h> #include <aidl/android/os/IHintManager.h> Loading Loading @@ -148,10 +149,36 @@ private: std::future<bool> mChannelCreationFinished; std::future<bool> mChannelCreationFinished; }; }; class SupportInfoWrapper { public: SupportInfoWrapper(hal::SupportInfo& info); bool isSessionModeSupported(hal::SessionMode mode); bool isSessionHintSupported(hal::SessionHint hint); private: template <class T> bool getEnumSupportFromBitfield(T& enumValue, int64_t& supportBitfield) { // extract the bit corresponding to the enum by shifting the bitfield // over that much and cutting off any extra values return (supportBitfield >> static_cast<int>(enumValue)) % 2; } hal::SupportInfo mSupportInfo; }; class HintManagerClient : public IHintManager::BnHintManagerClient { public: // Currently a no-op that exists for FMQ init to call in the future ndk::ScopedAStatus receiveChannelConfig(const hal::ChannelConfig&) { return ndk::ScopedAStatus::ok(); } }; struct APerformanceHintManager { struct APerformanceHintManager { public: public: static APerformanceHintManager* getInstance(); static APerformanceHintManager* getInstance(); APerformanceHintManager(std::shared_ptr<IHintManager>& service, int64_t preferredRateNanos); APerformanceHintManager(std::shared_ptr<IHintManager>& service, IHintManager::HintManagerClientData&& clientData, std::shared_ptr<HintManagerClient> callbackClient); APerformanceHintManager() = delete; APerformanceHintManager() = delete; ~APerformanceHintManager(); ~APerformanceHintManager(); Loading @@ -169,29 +196,21 @@ public: FMQWrapper& getFMQWrapper(); FMQWrapper& getFMQWrapper(); bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex); bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex); void initJava(JNIEnv* _Nonnull env); void initJava(JNIEnv* _Nonnull env); ndk::ScopedAIBinder_Weak x; template <class T> template <class T> static void layersFromNativeSurfaces(ANativeWindow** windows, int numWindows, static void layersFromNativeSurfaces(ANativeWindow** windows, int numWindows, ASurfaceControl** controls, int numSurfaceControls, ASurfaceControl** controls, int numSurfaceControls, std::vector<T>& out); std::vector<T>& out); ndk::SpAIBinder& getToken(); SupportInfoWrapper& getSupportInfo(); private: private: // Necessary to create an empty binder object static void* tokenStubOnCreate(void*) { return nullptr; } static void tokenStubOnDestroy(void*) {} static binder_status_t tokenStubOnTransact(AIBinder*, transaction_code_t, const AParcel*, AParcel*) { return STATUS_OK; } static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager); static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager); std::shared_ptr<IHintManager> mHintManager; std::shared_ptr<IHintManager> mHintManager; std::shared_ptr<HintManagerClient> mCallbackClient; IHintManager::HintManagerClientData mClientData; SupportInfoWrapper mSupportInfoWrapper; ndk::SpAIBinder mToken; ndk::SpAIBinder mToken; const int64_t mPreferredRateNanos; std::optional<int32_t> mMaxGraphicsPipelineThreadsCount; FMQWrapper mFMQWrapper; FMQWrapper mFMQWrapper; double mHintBudget = kMaxLoadHintsPerInterval; double mHintBudget = kMaxLoadHintsPerInterval; int64_t mLastBudgetReplenish = 0; int64_t mLastBudgetReplenish = 0; Loading Loading @@ -273,14 +292,27 @@ static FMQWrapper& getFMQ() { return APerformanceHintManager::getInstance()->getFMQWrapper(); return APerformanceHintManager::getInstance()->getFMQWrapper(); } } // ===================================== SupportInfoWrapper implementation SupportInfoWrapper::SupportInfoWrapper(hal::SupportInfo& info) : mSupportInfo(info) {} bool SupportInfoWrapper::isSessionHintSupported(hal::SessionHint hint) { return getEnumSupportFromBitfield(hint, mSupportInfo.sessionHints); } bool SupportInfoWrapper::isSessionModeSupported(hal::SessionMode mode) { return getEnumSupportFromBitfield(mode, mSupportInfo.sessionModes); } // ===================================== APerformanceHintManager implementation // ===================================== APerformanceHintManager implementation APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager>& manager, APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager>& manager, int64_t preferredRateNanos) IHintManager::HintManagerClientData&& clientData, : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) { std::shared_ptr<HintManagerClient> callbackClient) static AIBinder_Class* tokenBinderClass = : mHintManager(std::move(manager)), AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy, mCallbackClient(callbackClient), tokenStubOnTransact); mClientData(clientData), mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr)); mSupportInfoWrapper(clientData.supportInfo), mToken(callbackClient->asBinder()) { if (mFMQWrapper.isSupported()) { if (mFMQWrapper.isSupported()) { mFMQWrapper.setToken(mToken); mFMQWrapper.setToken(mToken); mFMQWrapper.startChannel(mHintManager.get()); mFMQWrapper.startChannel(mHintManager.get()); Loading Loading @@ -315,16 +347,17 @@ APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintMa ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__); ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__); return nullptr; return nullptr; } } int64_t preferredRateNanos = -1L; std::shared_ptr<HintManagerClient> client = ndk::SharedRefBase::make<HintManagerClient>(); ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos); IHintManager::HintManagerClientData clientData; ndk::ScopedAStatus ret = manager->registerClient(client, &clientData); if (!ret.isOk()) { if (!ret.isOk()) { ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage()); ALOGE("%s: PerformanceHint is not supported. %s", __FUNCTION__, ret.getMessage()); return nullptr; return nullptr; } } if (preferredRateNanos <= 0) { if (clientData.preferredRateNanos <= 0) { preferredRateNanos = -1L; clientData.preferredRateNanos = -1L; } } return new APerformanceHintManager(manager, preferredRateNanos); return new APerformanceHintManager(manager, std::move(clientData), client); } } bool APerformanceHintManager::canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) { bool APerformanceHintManager::canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) { Loading Loading @@ -389,7 +422,9 @@ APerformanceHintSession* APerformanceHintManager::createSessionUsingConfig( ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage()); ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage()); return nullptr; return nullptr; } } auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos, auto out = new APerformanceHintSession(mHintManager, std::move(session), mClientData.preferredRateNanos, sessionCreationConfig->targetWorkDurationNanos, isJava, sessionCreationConfig->targetWorkDurationNanos, isJava, sessionConfig.id == -1 sessionConfig.id == -1 ? std::nullopt ? std::nullopt Loading @@ -416,24 +451,11 @@ APerformanceHintSession* APerformanceHintManager::getSessionFromJava(JNIEnv* env } } int64_t APerformanceHintManager::getPreferredRateNanos() const { int64_t APerformanceHintManager::getPreferredRateNanos() const { return mPreferredRateNanos; return mClientData.preferredRateNanos; } } int32_t APerformanceHintManager::getMaxGraphicsPipelineThreadsCount() { int32_t APerformanceHintManager::getMaxGraphicsPipelineThreadsCount() { if (!mMaxGraphicsPipelineThreadsCount.has_value()) { return mClientData.maxGraphicsPipelineThreads; int32_t threadsCount = -1; ndk::ScopedAStatus ret = mHintManager->getMaxGraphicsPipelineThreadsCount(&threadsCount); if (!ret.isOk()) { ALOGE("%s: PerformanceHint cannot get max graphics pipeline threads count. %s", __FUNCTION__, ret.getMessage()); return -1; } if (threadsCount <= 0) { threadsCount = -1; } mMaxGraphicsPipelineThreadsCount.emplace(threadsCount); } return mMaxGraphicsPipelineThreadsCount.value(); } } FMQWrapper& APerformanceHintManager::getFMQWrapper() { FMQWrapper& APerformanceHintManager::getFMQWrapper() { Loading @@ -450,6 +472,14 @@ void APerformanceHintManager::initJava(JNIEnv* _Nonnull env) { mJavaInitialized = true; mJavaInitialized = true; } } ndk::SpAIBinder& APerformanceHintManager::getToken() { return mToken; } SupportInfoWrapper& APerformanceHintManager::getSupportInfo() { return mSupportInfoWrapper; } // ===================================== APerformanceHintSession implementation // ===================================== APerformanceHintSession implementation constexpr int kNumEnums = enum_size<hal::SessionHint>(); constexpr int kNumEnums = enum_size<hal::SessionHint>(); Loading
native/android/tests/performance_hint/PerformanceHintNativeTest.cpp +22 −13 Original line number Original line Diff line number Diff line Loading @@ -56,9 +56,6 @@ public: const SessionCreationConfig& creationConfig, hal::SessionConfig* config, const SessionCreationConfig& creationConfig, hal::SessionConfig* config, std::shared_ptr<IHintSession>* _aidl_return), std::shared_ptr<IHintSession>* _aidl_return), (override)); (override)); MOCK_METHOD(ScopedAStatus, getHintSessionPreferredRate, (int64_t * _aidl_return), (override)); MOCK_METHOD(ScopedAStatus, getMaxGraphicsPipelineThreadsCount, (int32_t* _aidl_return), (override)); MOCK_METHOD(ScopedAStatus, setHintSessionThreads, MOCK_METHOD(ScopedAStatus, setHintSessionThreads, (const std::shared_ptr<IHintSession>& hintSession, (const std::shared_ptr<IHintSession>& hintSession, const ::std::vector<int32_t>& tids), const ::std::vector<int32_t>& tids), Loading @@ -84,6 +81,11 @@ public: MOCK_METHOD(ScopedAStatus, getGpuHeadroomMinIntervalMillis, (int64_t* _aidl_return), MOCK_METHOD(ScopedAStatus, getGpuHeadroomMinIntervalMillis, (int64_t* _aidl_return), (override)); (override)); MOCK_METHOD(ScopedAStatus, passSessionManagerBinder, (const SpAIBinder& sessionManager)); MOCK_METHOD(ScopedAStatus, passSessionManagerBinder, (const SpAIBinder& sessionManager)); MOCK_METHOD(ScopedAStatus, registerClient, (const std::shared_ptr<::aidl::android::os::IHintManager::IHintManagerClient>& clientDataIn, ::aidl::android::os::IHintManager::HintManagerClientData* _aidl_return), (override)); MOCK_METHOD(SpAIBinder, asBinder, (), (override)); MOCK_METHOD(SpAIBinder, asBinder, (), (override)); MOCK_METHOD(bool, isRemote, (), (override)); MOCK_METHOD(bool, isRemote, (), (override)); }; }; Loading Loading @@ -125,10 +127,9 @@ public: APerformanceHintManager* createManager() { APerformanceHintManager* createManager() { APerformanceHint_setUseFMQForTesting(mUsingFMQ); APerformanceHint_setUseFMQForTesting(mUsingFMQ); ON_CALL(*mMockIHintManager, getHintSessionPreferredRate(_)) ON_CALL(*mMockIHintManager, registerClient(_, _)) .WillByDefault(DoAll(SetArgPointee<0>(123L), [] { return ScopedAStatus::ok(); })); .WillByDefault( ON_CALL(*mMockIHintManager, getMaxGraphicsPipelineThreadsCount(_)) DoAll(SetArgPointee<1>(mClientData), [] { return ScopedAStatus::ok(); })); .WillByDefault(DoAll(SetArgPointee<0>(5), [] { return ScopedAStatus::ok(); })); return APerformanceHint_getManager(); return APerformanceHint_getManager(); } } Loading Loading @@ -238,6 +239,20 @@ public: int kMockQueueSize = 20; int kMockQueueSize = 20; bool mUsingFMQ = false; bool mUsingFMQ = false; IHintManager::HintManagerClientData mClientData{ .powerHalVersion = 6, .maxGraphicsPipelineThreads = 5, .preferredRateNanos = 123L, .supportInfo{ .usesSessions = true, .boosts = 0, .modes = 0, .sessionHints = -1, .sessionModes = -1, .sessionTags = -1, }, }; int32_t mMaxLoadHintsPerInterval; int32_t mMaxLoadHintsPerInterval; int64_t mLoadHintInterval; int64_t mLoadHintInterval; Loading @@ -256,12 +271,6 @@ bool equalsWithoutTimestamp(hal::WorkDuration lhs, hal::WorkDuration rhs) { lhs.gpuDurationNanos == rhs.gpuDurationNanos && lhs.durationNanos == rhs.durationNanos; lhs.gpuDurationNanos == rhs.gpuDurationNanos && lhs.durationNanos == rhs.durationNanos; } } TEST_F(PerformanceHintTest, TestGetPreferredUpdateRateNanos) { APerformanceHintManager* manager = createManager(); int64_t preferredUpdateRateNanos = APerformanceHint_getPreferredUpdateRateNanos(manager); EXPECT_EQ(123L, preferredUpdateRateNanos); } TEST_F(PerformanceHintTest, TestSession) { TEST_F(PerformanceHintTest, TestSession) { APerformanceHintManager* manager = createManager(); APerformanceHintManager* manager = createManager(); APerformanceHintSession* session = createSession(manager); APerformanceHintSession* session = createSession(manager); Loading
services/core/java/com/android/server/power/hint/HintManagerService.java +49 −10 Original line number Original line Diff line number Diff line Loading @@ -296,7 +296,11 @@ public final class HintManagerService extends SystemService { mPowerHalVersion = 0; mPowerHalVersion = 0; mUsesFmq = false; mUsesFmq = false; if (mPowerHal != null) { if (mPowerHal != null) { try { mSupportInfo = getSupportInfo(); mSupportInfo = getSupportInfo(); } catch (RemoteException e) { throw new IllegalStateException("Could not contact PowerHAL!", e); } } } mDefaultCpuHeadroomCalculationWindowMillis = mDefaultCpuHeadroomCalculationWindowMillis = new CpuHeadroomParamsInternal().calculationWindowMillis; new CpuHeadroomParamsInternal().calculationWindowMillis; Loading @@ -314,7 +318,7 @@ public final class HintManagerService extends SystemService { } } } } SupportInfo getSupportInfo() { SupportInfo getSupportInfo() throws RemoteException { try { try { mPowerHalVersion = mPowerHal.getInterfaceVersion(); mPowerHalVersion = mPowerHal.getInterfaceVersion(); if (mPowerHalVersion >= 6) { if (mPowerHalVersion >= 6) { Loading @@ -325,9 +329,40 @@ public final class HintManagerService extends SystemService { } } SupportInfo supportInfo = new SupportInfo(); SupportInfo supportInfo = new SupportInfo(); supportInfo.usesSessions = isHintSessionSupported(); // Global boosts & modes aren't currently relevant for HMS clients supportInfo.boosts = 0; supportInfo.modes = 0; supportInfo.sessionHints = 0; supportInfo.sessionModes = 0; supportInfo.sessionTags = 0; supportInfo.headroom = new SupportInfo.HeadroomSupportInfo(); supportInfo.headroom = new SupportInfo.HeadroomSupportInfo(); supportInfo.headroom.isCpuSupported = false; supportInfo.headroom.isCpuSupported = false; supportInfo.headroom.isGpuSupported = false; supportInfo.headroom.isGpuSupported = false; if (isHintSessionSupported()) { if (mPowerHalVersion == 4) { // Assume we support the V4 hints & modes unless specified // otherwise; this is to avoid breaking backwards compat // since we historically just assumed they were. supportInfo.sessionHints = 31; // first 5 bits are ones } if (mPowerHalVersion == 5) { // Assume we support the V5 hints & modes unless specified // otherwise; this is to avoid breaking backwards compat // since we historically just assumed they were. // Hal V5 has 8 modes, all of which it assumes are supported, // so we represent that by having the first 8 bits set supportInfo.sessionHints = 255; // first 8 bits are ones // Hal V5 has 1 mode which it assumes is supported, so we // represent that by having the first bit set supportInfo.sessionModes = 1; // Hal V5 has 5 tags, all of which it assumes are supported, // so we represent that by having the first 5 bits set supportInfo.sessionTags = 31; } } return supportInfo; return supportInfo; } } Loading Loading @@ -1228,7 +1263,7 @@ public final class HintManagerService extends SystemService { @SessionTag int tag, SessionCreationConfig creationConfig, @SessionTag int tag, SessionCreationConfig creationConfig, SessionConfig config) { SessionConfig config) { if (!isHintSessionSupported()) { if (!isHintSessionSupported()) { throw new UnsupportedOperationException("PowerHAL is not supported!"); throw new UnsupportedOperationException("PowerHintSessions are not supported!"); } } java.util.Objects.requireNonNull(token); java.util.Objects.requireNonNull(token); Loading Loading @@ -1424,12 +1459,6 @@ public final class HintManagerService extends SystemService { removeChannelItem(callingTgid, callingUid); removeChannelItem(callingTgid, callingUid); }; }; @Override public long getHintSessionPreferredRate() { return mHintSessionPreferredRate; } @Override public int getMaxGraphicsPipelineThreadsCount() { public int getMaxGraphicsPipelineThreadsCount() { return MAX_GRAPHICS_PIPELINE_THREADS_COUNT; return MAX_GRAPHICS_PIPELINE_THREADS_COUNT; } } Loading Loading @@ -1561,6 +1590,16 @@ public final class HintManagerService extends SystemService { mSessionManager = ISessionManager.Stub.asInterface(sessionManager); mSessionManager = ISessionManager.Stub.asInterface(sessionManager); } } public IHintManager.HintManagerClientData registerClient(@NonNull IHintManager.IHintManagerClient clientBinder) { IHintManager.HintManagerClientData out = new IHintManager.HintManagerClientData(); out.preferredRateNanos = mHintSessionPreferredRate; out.maxGraphicsPipelineThreads = getMaxGraphicsPipelineThreadsCount(); out.powerHalVersion = mPowerHalVersion; out.supportInfo = mSupportInfo; return out; } @Override @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) { if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) { Loading @@ -1568,7 +1607,7 @@ public final class HintManagerService extends SystemService { } } pw.println("HintSessionPreferredRate: " + mHintSessionPreferredRate); pw.println("HintSessionPreferredRate: " + mHintSessionPreferredRate); pw.println("MaxGraphicsPipelineThreadsCount: " + MAX_GRAPHICS_PIPELINE_THREADS_COUNT); pw.println("MaxGraphicsPipelineThreadsCount: " + MAX_GRAPHICS_PIPELINE_THREADS_COUNT); pw.println("HAL Support: " + isHintSessionSupported()); pw.println("Hint Session Support: " + isHintSessionSupported()); pw.println("Active Sessions:"); pw.println("Active Sessions:"); synchronized (mLock) { synchronized (mLock) { for (int i = 0; i < mActiveSessions.size(); i++) { for (int i = 0; i < mActiveSessions.size(); i++) { Loading
services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java +90 −8 Original line number Original line Diff line number Diff line Loading @@ -64,6 +64,7 @@ import android.os.Binder; import android.os.CpuHeadroomParamsInternal; import android.os.CpuHeadroomParamsInternal; import android.os.GpuHeadroomParamsInternal; import android.os.GpuHeadroomParamsInternal; import android.os.IBinder; import android.os.IBinder; import android.os.IHintManager; import android.os.IHintSession; import android.os.IHintSession; import android.os.PerformanceHintManager; import android.os.PerformanceHintManager; import android.os.Process; import android.os.Process; Loading Loading @@ -154,6 +155,8 @@ public class HintManagerServiceTest { private ActivityManagerInternal mAmInternalMock; private ActivityManagerInternal mAmInternalMock; @Mock @Mock private PackageManager mMockPackageManager; private PackageManager mMockPackageManager; @Mock private IHintManager.IHintManagerClient mClientCallback; @Rule @Rule public final CheckFlagsRule mCheckFlagsRule = public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); DeviceFlagsValueProvider.createCheckFlagsRule(); Loading @@ -171,6 +174,23 @@ public class HintManagerServiceTest { }; }; } } private SupportInfo makeDefaultSupportInfo() { mSupportInfo = new SupportInfo(); mSupportInfo.usesSessions = true; // By default, mark everything as fully supported mSupportInfo.sessionHints = -1; mSupportInfo.sessionModes = -1; mSupportInfo.modes = -1; mSupportInfo.boosts = -1; mSupportInfo.sessionTags = -1; mSupportInfo.headroom = new SupportInfo.HeadroomSupportInfo(); mSupportInfo.headroom.isCpuSupported = true; mSupportInfo.headroom.cpuMinIntervalMillis = 2000; mSupportInfo.headroom.isGpuSupported = true; mSupportInfo.headroom.gpuMinIntervalMillis = 2000; return mSupportInfo; } @Before @Before public void setUp() throws Exception { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this); Loading @@ -181,12 +201,7 @@ public class HintManagerServiceTest { mConfig.eventFlagDescriptor = new MQDescriptor<Byte, Byte>(); mConfig.eventFlagDescriptor = new MQDescriptor<Byte, Byte>(); ApplicationInfo applicationInfo = new ApplicationInfo(); ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.category = ApplicationInfo.CATEGORY_GAME; applicationInfo.category = ApplicationInfo.CATEGORY_GAME; mSupportInfo = new SupportInfo(); mSupportInfo = makeDefaultSupportInfo(); mSupportInfo.headroom = new SupportInfo.HeadroomSupportInfo(); mSupportInfo.headroom.isCpuSupported = true; mSupportInfo.headroom.cpuMinIntervalMillis = 2000; mSupportInfo.headroom.isGpuSupported = true; mSupportInfo.headroom.gpuMinIntervalMillis = 2000; when(mContext.getPackageManager()).thenReturn(mMockPackageManager); when(mContext.getPackageManager()).thenReturn(mMockPackageManager); when(mMockPackageManager.getNameForUid(anyInt())).thenReturn(TEST_APP_NAME); when(mMockPackageManager.getNameForUid(anyInt())).thenReturn(TEST_APP_NAME); when(mMockPackageManager.getApplicationInfo(eq(TEST_APP_NAME), anyInt())) when(mMockPackageManager.getApplicationInfo(eq(TEST_APP_NAME), anyInt())) Loading Loading @@ -215,6 +230,7 @@ public class HintManagerServiceTest { when(mIPowerMock.getInterfaceVersion()).thenReturn(6); when(mIPowerMock.getInterfaceVersion()).thenReturn(6); when(mIPowerMock.getSupportInfo()).thenReturn(mSupportInfo); when(mIPowerMock.getSupportInfo()).thenReturn(mSupportInfo); when(mIPowerMock.getSessionChannel(anyInt(), anyInt())).thenReturn(mConfig); when(mIPowerMock.getSessionChannel(anyInt(), anyInt())).thenReturn(mConfig); when(mIPowerMock.getSupportInfo()).thenReturn(mSupportInfo); LocalServices.removeServiceForTest(ActivityManagerInternal.class); LocalServices.removeServiceForTest(ActivityManagerInternal.class); LocalServices.addService(ActivityManagerInternal.class, mAmInternalMock); LocalServices.addService(ActivityManagerInternal.class, mAmInternalMock); } } Loading Loading @@ -409,8 +425,11 @@ public class HintManagerServiceTest { HintManagerService service = createService(); HintManagerService service = createService(); IBinder token = new Binder(); IBinder token = new Binder(); final int threadCount = IHintManager.HintManagerClientData data = service.getBinderServiceInstance() service.getBinderServiceInstance().getMaxGraphicsPipelineThreadsCount(); .registerClient(mClientCallback); final int threadCount = data.maxGraphicsPipelineThreads; long sessionPtr1 = 1111L; long sessionPtr1 = 1111L; long sessionId1 = 11111L; long sessionId1 = 11111L; CountDownLatch stopLatch1 = new CountDownLatch(1); CountDownLatch stopLatch1 = new CountDownLatch(1); Loading Loading @@ -1400,4 +1419,67 @@ public class HintManagerServiceTest { verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams1)); verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams1)); verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2)); verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2)); } } @Test public void testRegisteringClient() throws Exception { HintManagerService service = createService(); IHintManager.HintManagerClientData data = service.getBinderServiceInstance() .registerClient(mClientCallback); assertNotNull(data); assertEquals(data.supportInfo, mSupportInfo); } @Test public void testRegisteringClientOnV4() throws Exception { when(mIPowerMock.getInterfaceVersion()).thenReturn(4); HintManagerService service = createService(); IHintManager.HintManagerClientData data = service.getBinderServiceInstance() .registerClient(mClientCallback); assertNotNull(data); assertEquals(data.supportInfo.usesSessions, true); assertEquals(data.supportInfo.boosts, 0); assertEquals(data.supportInfo.modes, 0); assertEquals(data.supportInfo.sessionHints, 31); assertEquals(data.supportInfo.sessionModes, 0); assertEquals(data.supportInfo.sessionTags, 0); assertEquals(data.powerHalVersion, 4); assertEquals(data.preferredRateNanos, DEFAULT_HINT_PREFERRED_RATE); } @Test public void testRegisteringClientOnV5() throws Exception { when(mIPowerMock.getInterfaceVersion()).thenReturn(5); HintManagerService service = createService(); IHintManager.HintManagerClientData data = service.getBinderServiceInstance() .registerClient(mClientCallback); assertNotNull(data); assertEquals(data.supportInfo.usesSessions, true); assertEquals(data.supportInfo.boosts, 0); assertEquals(data.supportInfo.modes, 0); assertEquals(data.supportInfo.sessionHints, 255); assertEquals(data.supportInfo.sessionModes, 1); assertEquals(data.supportInfo.sessionTags, 31); assertEquals(data.powerHalVersion, 5); assertEquals(data.preferredRateNanos, DEFAULT_HINT_PREFERRED_RATE); } @Test public void testSettingUpOldClientWhenUnsupported() throws Exception { when(mIPowerMock.getInterfaceVersion()).thenReturn(5); // Mock unsupported to modify the default support behavior when(mNativeWrapperMock.halGetHintSessionPreferredRate()) .thenReturn(-1L); HintManagerService service = createService(); IHintManager.HintManagerClientData data = service.getBinderServiceInstance() .registerClient(mClientCallback); assertNotNull(data); assertEquals(data.supportInfo.usesSessions, false); assertEquals(data.supportInfo.boosts, 0); assertEquals(data.supportInfo.modes, 0); assertEquals(data.supportInfo.sessionHints, 0); assertEquals(data.supportInfo.sessionModes, 0); assertEquals(data.supportInfo.sessionTags, 0); assertEquals(data.powerHalVersion, 5); assertEquals(data.preferredRateNanos, -1); } } }