Implement NDK createSessionUsingConfig API
This patch implements a new way to create ADPF hint session,
with a new pacelable SessionCreationConfig. This object encapsulates
the required information for session creation, with a set of setters to
assign values to those fields in the session creation config.
This object can be reused on the client side in order to streamline
the session creation process.
Bug: 362801903
Bug: 367803904
Test: atest HintManagerServiceTest
atest PerformanceHintNativeTest
Flag: EXEMPT_NDK
Change-Id: I12baa7064573a8281f034c1e0280d06947d97f30
diff --git a/core/java/Android.bp b/core/java/Android.bp
index bc38294..bdd7a37 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -236,6 +236,7 @@
"android/os/GpuHeadroomParamsInternal.aidl",
"android/os/IHintManager.aidl",
"android/os/IHintSession.aidl",
+ "android/os/SessionCreationConfig.aidl",
],
unstable: true,
backend: {
diff --git a/core/java/android/os/IHintManager.aidl b/core/java/android/os/IHintManager.aidl
index 3312055..a043da9 100644
--- a/core/java/android/os/IHintManager.aidl
+++ b/core/java/android/os/IHintManager.aidl
@@ -20,6 +20,7 @@
import android.os.CpuHeadroomParamsInternal;
import android.os.GpuHeadroomParamsInternal;
import android.os.IHintSession;
+import android.os.SessionCreationConfig;
import android.hardware.power.ChannelConfig;
import android.hardware.power.SessionConfig;
import android.hardware.power.SessionTag;
@@ -34,8 +35,8 @@
* Throws UnsupportedOperationException if ADPF is not supported, and IllegalStateException
* if creation is supported but fails.
*/
- IHintSession createHintSessionWithConfig(in IBinder token, in int[] threadIds,
- in long durationNanos, in SessionTag tag, out SessionConfig config);
+ IHintSession createHintSessionWithConfig(in IBinder token, in SessionTag tag,
+ in SessionCreationConfig creationConfig, out SessionConfig config);
/**
* Get preferred rate limit in nanoseconds.
@@ -56,4 +57,9 @@
long getCpuHeadroomMinIntervalMillis();
float getGpuHeadroom(in GpuHeadroomParamsInternal params);
long getGpuHeadroomMinIntervalMillis();
+
+ /**
+ * Get Maximum number of graphics pipeline threads allowed per-app.
+ */
+ int getMaxGraphicsPipelineThreadsCount();
}
diff --git a/core/java/android/os/SessionCreationConfig.aidl b/core/java/android/os/SessionCreationConfig.aidl
new file mode 100644
index 0000000..cdc0ef4
--- /dev/null
+++ b/core/java/android/os/SessionCreationConfig.aidl
@@ -0,0 +1,39 @@
+/*
+ *
+ * Copyright 2024, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.hardware.power.SessionTag;
+import android.hardware.power.SessionMode;
+
+/** {@hide} */
+parcelable SessionCreationConfig {
+ /**
+ * List of tids to be included in the hint session.
+ */
+ int[] tids;
+
+ /**
+ * The initial target work duration of this hint session in nanoseconds.
+ */
+ long targetWorkDurationNanos;
+
+ /**
+ * List of the modes to be enabled upon session creation.
+ */
+ SessionMode[] modesToEnable;
+}
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index 2ef8764..5ac53f1 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -12,6 +12,15 @@
}
flag {
+ name: "adpf_graphics_pipeline"
+ is_exported: true
+ namespace: "game"
+ description: "Guards use of SessionCreationConfig and Graphics Pipeline mode"
+ is_fixed_read_only: true
+ bug: "367803904"
+}
+
+flag {
name: "adpf_hwui_gpu"
namespace: "game"
description: "Guards use of the FMQ channel for ADPF"
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 6b41ddd..9da7bec 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -355,12 +355,14 @@
APerformanceHint_getManager; # introduced=Tiramisu
APerformanceHint_createSession; # introduced=Tiramisu
APerformanceHint_getPreferredUpdateRateNanos; # introduced=Tiramisu
+ APerformanceHint_getMaxGraphicsPipelineThreadsCount; # introduced=36
APerformanceHint_updateTargetWorkDuration; # introduced=Tiramisu
APerformanceHint_reportActualWorkDuration; # introduced=Tiramisu
APerformanceHint_closeSession; # introduced=Tiramisu
APerformanceHint_setThreads; # introduced=UpsideDownCake
APerformanceHint_setPreferPowerEfficiency; # introduced=VanillaIceCream
APerformanceHint_reportActualWorkDuration2; # introduced=VanillaIceCream
+ APerformanceHint_createSessionUsingConfig; # introduced=36
APerformanceHint_notifyWorkloadIncrease; # introduced=36
APerformanceHint_notifyWorkloadReset; # introduced=36
APerformanceHint_borrowSessionFromJava; # introduced=36
@@ -370,6 +372,12 @@
AWorkDuration_setActualTotalDurationNanos; # introduced=VanillaIceCream
AWorkDuration_setActualCpuDurationNanos; # introduced=VanillaIceCream
AWorkDuration_setActualGpuDurationNanos; # introduced=VanillaIceCream
+ ASessionCreationConfig_create; # introduced=36
+ ASessionCreationConfig_release; # introduced=36
+ ASessionCreationConfig_setTids; # introduced=36
+ ASessionCreationConfig_setTargetWorkDurationNanos; # introduced=36
+ ASessionCreationConfig_setPreferPowerEfficiency; # introduced=36
+ ASessionCreationConfig_setGraphicsPipeline; # introduced=36
local:
*;
};
@@ -379,8 +387,10 @@
AThermal_setIThermalServiceForTesting;
APerformanceHint_setIHintManagerForTesting;
APerformanceHint_sendHint;
+ APerformanceHint_setUseGraphicsPipelineForTesting;
APerformanceHint_getThreadIds;
APerformanceHint_createSessionInternal;
+ APerformanceHint_createSessionUsingConfigInternal;
APerformanceHint_setUseFMQForTesting;
APerformanceHint_getRateLimiterPropertiesForTesting;
APerformanceHint_setUseNewLoadHintBehaviorForTesting;
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index bc1945e..c67e93c 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -26,6 +26,7 @@
#include <aidl/android/hardware/power/WorkDurationFixedV1.h>
#include <aidl/android/os/IHintManager.h>
#include <aidl/android/os/IHintSession.h>
+#include <aidl/android/os/SessionCreationConfig.h>
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
#include <android/binder_manager.h>
@@ -65,6 +66,13 @@
constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count();
struct AWorkDuration : public hal::WorkDuration {};
+struct ASessionCreationConfig : public SessionCreationConfig {};
+
+bool kForceGraphicsPipeline = false;
+
+bool useGraphicsPipeline() {
+ return android::os::adpf_graphics_pipeline() || kForceGraphicsPipeline;
+}
// A pair of values that determine the behavior of the
// load hint rate limiter, to only allow "X hints every Y seconds"
@@ -142,7 +150,11 @@
bool isJava = false);
APerformanceHintSession* getSessionFromJava(JNIEnv* _Nonnull env, jobject _Nonnull sessionObj);
+ APerformanceHintSession* createSessionUsingConfig(ASessionCreationConfig* sessionCreationConfig,
+ hal::SessionTag tag = hal::SessionTag::APP,
+ bool isJava = false);
int64_t getPreferredRateNanos() const;
+ int32_t getMaxGraphicsPipelineThreadsCount();
FMQWrapper& getFMQWrapper();
bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex);
void initJava(JNIEnv* _Nonnull env);
@@ -163,6 +175,7 @@
std::shared_ptr<IHintManager> mHintManager;
ndk::SpAIBinder mToken;
const int64_t mPreferredRateNanos;
+ std::optional<int32_t> mMaxGraphicsPipelineThreadsCount;
FMQWrapper mFMQWrapper;
double mHintBudget = kMaxLoadHintsPerInterval;
int64_t mLastBudgetReplenish = 0;
@@ -220,8 +233,10 @@
std::vector<int32_t> mLastThreadIDs GUARDED_BY(sHintMutex);
std::optional<hal::SessionConfig> mSessionConfig GUARDED_BY(sHintMutex);
// Tracing helpers
- void traceThreads(std::vector<int32_t>& tids) REQUIRES(sHintMutex);
+ void traceThreads(const std::vector<int32_t>& tids) REQUIRES(sHintMutex);
void tracePowerEfficient(bool powerEfficient);
+ void traceGraphicsPipeline(bool graphicsPipeline);
+ void traceModes(const std::vector<hal::SessionMode>& modesToEnable);
void traceActualDuration(int64_t actualDuration);
void traceBatchSize(size_t batchSize);
void traceTargetDuration(int64_t targetDuration);
@@ -311,27 +326,45 @@
APerformanceHintSession* APerformanceHintManager::createSession(
const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos,
hal::SessionTag tag, bool isJava) {
- std::vector<int32_t> tids(threadIds, threadIds + size);
- std::shared_ptr<IHintSession> session;
ndk::ScopedAStatus ret;
hal::SessionConfig sessionConfig{.id = -1};
- ret = mHintManager->createHintSessionWithConfig(mToken, tids, initialTargetWorkDurationNanos,
- tag, &sessionConfig, &session);
+
+ SessionCreationConfig creationConfig{
+ .tids = std::vector<int32_t>(threadIds, threadIds + size),
+ .targetWorkDurationNanos = initialTargetWorkDurationNanos,
+ };
+
+ return APerformanceHintManager::createSessionUsingConfig(static_cast<ASessionCreationConfig*>(
+ &creationConfig),
+ tag, isJava);
+}
+
+APerformanceHintSession* APerformanceHintManager::createSessionUsingConfig(
+ ASessionCreationConfig* sessionCreationConfig, hal::SessionTag tag, bool isJava) {
+ std::shared_ptr<IHintSession> session;
+ hal::SessionConfig sessionConfig{.id = -1};
+ ndk::ScopedAStatus ret;
+
+ ret = mHintManager->createHintSessionWithConfig(mToken, tag,
+ *static_cast<SessionCreationConfig*>(
+ sessionCreationConfig),
+ &sessionConfig, &session);
if (!ret.isOk() || !session) {
ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage());
return nullptr;
}
auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
- initialTargetWorkDurationNanos, isJava,
+ sessionCreationConfig->targetWorkDurationNanos, isJava,
sessionConfig.id == -1
? std::nullopt
: std::make_optional<hal::SessionConfig>(
std::move(sessionConfig)));
std::scoped_lock lock(sHintMutex);
- out->traceThreads(tids);
- out->traceTargetDuration(initialTargetWorkDurationNanos);
- out->tracePowerEfficient(false);
+ out->traceThreads(sessionCreationConfig->tids);
+ out->traceTargetDuration(sessionCreationConfig->targetWorkDurationNanos);
+ out->traceModes(sessionCreationConfig->modesToEnable);
+
return out;
}
@@ -351,6 +384,23 @@
return mPreferredRateNanos;
}
+int32_t APerformanceHintManager::getMaxGraphicsPipelineThreadsCount() {
+ if (!mMaxGraphicsPipelineThreadsCount.has_value()) {
+ 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() {
return mFMQWrapper;
}
@@ -787,7 +837,7 @@
// ===================================== Tracing helpers
-void APerformanceHintSession::traceThreads(std::vector<int32_t>& tids) {
+void APerformanceHintSession::traceThreads(const std::vector<int32_t>& tids) {
std::set<int32_t> tidSet{tids.begin(), tids.end()};
// Disable old TID tracing
@@ -813,6 +863,28 @@
ATrace_setCounter((mSessionName + " power efficiency mode").c_str(), powerEfficient);
}
+void APerformanceHintSession::traceGraphicsPipeline(bool graphicsPipeline) {
+ ATrace_setCounter((mSessionName + " graphics pipeline mode").c_str(), graphicsPipeline);
+}
+
+void APerformanceHintSession::traceModes(const std::vector<hal::SessionMode>& modesToEnable) {
+ // Iterate through all modes to trace, set to enable for all modes in modesToEnable,
+ // and set to disable for those are not.
+ for (hal::SessionMode mode :
+ {hal::SessionMode::POWER_EFFICIENCY, hal::SessionMode::GRAPHICS_PIPELINE}) {
+ bool isEnabled =
+ find(modesToEnable.begin(), modesToEnable.end(), mode) != modesToEnable.end();
+ switch (mode) {
+ case hal::SessionMode::POWER_EFFICIENCY:
+ tracePowerEfficient(isEnabled);
+ break;
+ case hal::SessionMode::GRAPHICS_PIPELINE:
+ traceGraphicsPipeline(isEnabled);
+ break;
+ }
+ }
+}
+
void APerformanceHintSession::traceActualDuration(int64_t actualDuration) {
ATrace_setCounter((mSessionName + " actual duration").c_str(), actualDuration);
}
@@ -855,6 +927,22 @@
return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
}
+APerformanceHintSession* APerformanceHint_createSessionUsingConfig(
+ APerformanceHintManager* manager, ASessionCreationConfig* sessionCreationConfig) {
+ VALIDATE_PTR(manager);
+ VALIDATE_PTR(sessionCreationConfig);
+ return manager->createSessionUsingConfig(sessionCreationConfig);
+}
+
+APerformanceHintSession* APerformanceHint_createSessionUsingConfigInternal(
+ APerformanceHintManager* manager, ASessionCreationConfig* sessionCreationConfig,
+ SessionTag tag) {
+ VALIDATE_PTR(manager);
+ VALIDATE_PTR(sessionCreationConfig);
+ return manager->createSessionUsingConfig(sessionCreationConfig,
+ static_cast<hal::SessionTag>(tag));
+}
+
APerformanceHintSession* APerformanceHint_createSessionInternal(
APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
int64_t initialTargetWorkDurationNanos, SessionTag tag) {
@@ -885,6 +973,11 @@
return manager->getPreferredRateNanos();
}
+int APerformanceHint_getMaxGraphicsPipelineThreadsCount(APerformanceHintManager* manager) {
+ VALIDATE_PTR(manager);
+ return manager->getMaxGraphicsPipelineThreadsCount();
+}
+
int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
int64_t targetDurationNanos) {
VALIDATE_PTR(session)
@@ -1018,6 +1111,81 @@
gForceFMQEnabled = enabled;
}
+ASessionCreationConfig* ASessionCreationConfig_create() {
+ return new ASessionCreationConfig();
+}
+
+void ASessionCreationConfig_release(ASessionCreationConfig* config) {
+ VALIDATE_PTR(config)
+
+ delete config;
+}
+
+int ASessionCreationConfig_setTids(ASessionCreationConfig* config, const pid_t* tids, size_t size) {
+ VALIDATE_PTR(config)
+ VALIDATE_PTR(tids)
+
+ if (!useGraphicsPipeline()) {
+ return ENOTSUP;
+ }
+
+ if (size <= 0) {
+ LOG_ALWAYS_FATAL_IF(size <= 0,
+ "%s: Invalid value. Thread id list size should be greater than zero.",
+ __FUNCTION__);
+ return EINVAL;
+ }
+ config->tids = std::vector<int32_t>(tids, tids + size);
+ return 0;
+}
+
+int ASessionCreationConfig_setTargetWorkDurationNanos(ASessionCreationConfig* config,
+ int64_t targetWorkDurationNanos) {
+ VALIDATE_PTR(config)
+ VALIDATE_INT(targetWorkDurationNanos, >= 0)
+
+ if (!useGraphicsPipeline()) {
+ return ENOTSUP;
+ }
+
+ config->targetWorkDurationNanos = targetWorkDurationNanos;
+ return 0;
+}
+
+int ASessionCreationConfig_setPreferPowerEfficiency(ASessionCreationConfig* config, bool enabled) {
+ VALIDATE_PTR(config)
+
+ if (!useGraphicsPipeline()) {
+ return ENOTSUP;
+ }
+
+ if (enabled) {
+ config->modesToEnable.push_back(hal::SessionMode::POWER_EFFICIENCY);
+ } else {
+ std::erase(config->modesToEnable, hal::SessionMode::POWER_EFFICIENCY);
+ }
+ return 0;
+}
+
+int ASessionCreationConfig_setGraphicsPipeline(ASessionCreationConfig* config, bool enabled) {
+ VALIDATE_PTR(config)
+
+ if (!useGraphicsPipeline()) {
+ return ENOTSUP;
+ }
+
+ if (enabled) {
+ config->modesToEnable.push_back(hal::SessionMode::GRAPHICS_PIPELINE);
+ } else {
+ std::erase(config->modesToEnable, hal::SessionMode::GRAPHICS_PIPELINE);
+ }
+ return 0;
+}
+
+void APerformanceHint_setUseGraphicsPipelineForTesting(bool enabled) {
+ kForceGraphicsPipeline = enabled;
+}
+
void APerformanceHint_getRateLimiterPropertiesForTesting(int32_t* maxLoadHintsPerInterval,
int64_t* loadHintInterval) {
*maxLoadHintsPerInterval = kMaxLoadHintsPerInterval;
diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
index f707a0e..c5fb808 100644
--- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
+++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
@@ -18,9 +18,11 @@
#include <aidl/android/hardware/power/ChannelConfig.h>
#include <aidl/android/hardware/power/SessionConfig.h>
+#include <aidl/android/hardware/power/SessionMode.h>
#include <aidl/android/hardware/power/SessionTag.h>
#include <aidl/android/hardware/power/WorkDuration.h>
#include <aidl/android/os/IHintManager.h>
+#include <aidl/android/os/SessionCreationConfig.h>
#include <android/binder_manager.h>
#include <android/binder_status.h>
#include <android/performance_hint.h>
@@ -36,6 +38,7 @@
namespace hal = aidl::android::hardware::power;
using aidl::android::os::IHintManager;
using aidl::android::os::IHintSession;
+using aidl::android::os::SessionCreationConfig;
using ndk::ScopedAStatus;
using ndk::SpAIBinder;
using HalChannelMessageContents = hal::ChannelMessage::ChannelMessageContents;
@@ -49,11 +52,13 @@
class MockIHintManager : public IHintManager {
public:
MOCK_METHOD(ScopedAStatus, createHintSessionWithConfig,
- (const SpAIBinder& token, const ::std::vector<int32_t>& tids, int64_t durationNanos,
- hal::SessionTag tag, hal::SessionConfig* config,
+ (const SpAIBinder& token, hal::SessionTag tag,
+ const SessionCreationConfig& creationConfig, hal::SessionConfig* config,
std::shared_ptr<IHintSession>* _aidl_return),
(override));
MOCK_METHOD(ScopedAStatus, getHintSessionPreferredRate, (int64_t * _aidl_return), (override));
+ MOCK_METHOD(ScopedAStatus, getMaxGraphicsPipelineThreadsCount, (int32_t* _aidl_return),
+ (override));
MOCK_METHOD(ScopedAStatus, setHintSessionThreads,
(const std::shared_ptr<IHintSession>& hintSession,
const ::std::vector<int32_t>& tids),
@@ -105,6 +110,7 @@
APerformanceHint_getRateLimiterPropertiesForTesting(&mMaxLoadHintsPerInterval,
&mLoadHintInterval);
APerformanceHint_setIHintManagerForTesting(&mMockIHintManager);
+ APerformanceHint_setUseGraphicsPipelineForTesting(true);
APerformanceHint_setUseNewLoadHintBehaviorForTesting(true);
}
@@ -118,21 +124,22 @@
APerformanceHint_setUseFMQForTesting(mUsingFMQ);
ON_CALL(*mMockIHintManager, getHintSessionPreferredRate(_))
.WillByDefault(DoAll(SetArgPointee<0>(123L), [] { return ScopedAStatus::ok(); }));
+ ON_CALL(*mMockIHintManager, getMaxGraphicsPipelineThreadsCount(_))
+ .WillByDefault(DoAll(SetArgPointee<0>(5), [] { return ScopedAStatus::ok(); }));
return APerformanceHint_getManager();
}
APerformanceHintSession* createSession(APerformanceHintManager* manager,
int64_t targetDuration = 56789L, bool isHwui = false) {
mMockSession = ndk::SharedRefBase::make<NiceMock<MockIHintSession>>();
- int64_t sessionId = 123;
+ const int64_t sessionId = 123;
std::vector<int32_t> tids;
tids.push_back(1);
tids.push_back(2);
- ON_CALL(*mMockIHintManager,
- createHintSessionWithConfig(_, Eq(tids), Eq(targetDuration), _, _, _))
- .WillByDefault(DoAll(SetArgPointee<4>(hal::SessionConfig({.id = sessionId})),
- SetArgPointee<5>(std::shared_ptr<IHintSession>(mMockSession)),
+ ON_CALL(*mMockIHintManager, createHintSessionWithConfig(_, _, _, _, _))
+ .WillByDefault(DoAll(SetArgPointee<3>(hal::SessionConfig({.id = sessionId})),
+ SetArgPointee<4>(std::shared_ptr<IHintSession>(mMockSession)),
[] { return ScopedAStatus::ok(); }));
ON_CALL(*mMockIHintManager, setHintSessionThreads(_, _)).WillByDefault([] {
@@ -157,6 +164,43 @@
return APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration);
}
+ APerformanceHintSession* createSessionUsingConfig(APerformanceHintManager* manager,
+ SessionCreationConfig config,
+ bool isHwui = false) {
+ mMockSession = ndk::SharedRefBase::make<NiceMock<MockIHintSession>>();
+ const int64_t sessionId = 123;
+
+ ON_CALL(*mMockIHintManager, createHintSessionWithConfig(_, _, _, _, _))
+ .WillByDefault(DoAll(SetArgPointee<3>(hal::SessionConfig({.id = sessionId})),
+ SetArgPointee<4>(std::shared_ptr<IHintSession>(mMockSession)),
+ [] { return ScopedAStatus::ok(); }));
+
+ ON_CALL(*mMockIHintManager, setHintSessionThreads(_, _)).WillByDefault([] {
+ return ScopedAStatus::ok();
+ });
+ ON_CALL(*mMockSession, sendHint(_)).WillByDefault([] { return ScopedAStatus::ok(); });
+ ON_CALL(*mMockSession, setMode(_, true)).WillByDefault([] { return ScopedAStatus::ok(); });
+ ON_CALL(*mMockSession, close()).WillByDefault([] { return ScopedAStatus::ok(); });
+ ON_CALL(*mMockSession, updateTargetWorkDuration(_)).WillByDefault([] {
+ return ScopedAStatus::ok();
+ });
+ ON_CALL(*mMockSession, reportActualWorkDuration(_, _)).WillByDefault([] {
+ return ScopedAStatus::ok();
+ });
+ ON_CALL(*mMockSession, reportActualWorkDuration2(_)).WillByDefault([] {
+ return ScopedAStatus::ok();
+ });
+
+ if (isHwui) {
+ return APerformanceHint_createSessionUsingConfigInternal(
+ manager, reinterpret_cast<ASessionCreationConfig*>(&config), SessionTag::HWUI);
+ }
+
+ return APerformanceHint_createSessionUsingConfig(manager,
+ reinterpret_cast<ASessionCreationConfig*>(
+ &config));
+ }
+
void setFMQEnabled(bool enabled) {
mUsingFMQ = enabled;
if (enabled) {
@@ -272,16 +316,26 @@
}
TEST_F(PerformanceHintTest, TestUpdatedSessionCreation) {
- EXPECT_CALL(*mMockIHintManager, createHintSessionWithConfig(_, _, _, _, _, _)).Times(1);
+ EXPECT_CALL(*mMockIHintManager, createHintSessionWithConfig(_, _, _, _, _)).Times(1);
APerformanceHintManager* manager = createManager();
APerformanceHintSession* session = createSession(manager);
ASSERT_TRUE(session);
APerformanceHint_closeSession(session);
}
+TEST_F(PerformanceHintTest, TestSessionCreationUsingConfig) {
+ EXPECT_CALL(*mMockIHintManager, createHintSessionWithConfig(_, _, _, _, _)).Times(1);
+ SessionCreationConfig config{.tids = std::vector<int32_t>(1, 2),
+ .targetWorkDurationNanos = 5678,
+ .modesToEnable = std::vector<hal::SessionMode>(0)};
+ APerformanceHintManager* manager = createManager();
+ APerformanceHintSession* session = createSessionUsingConfig(manager, config);
+ ASSERT_TRUE(session);
+ APerformanceHint_closeSession(session);
+}
+
TEST_F(PerformanceHintTest, TestHwuiSessionCreation) {
- EXPECT_CALL(*mMockIHintManager,
- createHintSessionWithConfig(_, _, _, hal::SessionTag::HWUI, _, _))
+ EXPECT_CALL(*mMockIHintManager, createHintSessionWithConfig(_, hal::SessionTag::HWUI, _, _, _))
.Times(1);
APerformanceHintManager* manager = createManager();
APerformanceHintSession* session = createSession(manager, 56789L, true);
@@ -447,3 +501,16 @@
reinterpret_cast<AWorkDuration*>(&duration));
expectToReadFromFmq<HalChannelMessageContents::Tag::workDuration>(durationExpected);
}
+
+TEST_F(PerformanceHintTest, TestASessionCreationConfig) {
+ ASessionCreationConfig* config = ASessionCreationConfig_create();
+ ASSERT_NE(config, nullptr);
+
+ const int32_t testTids[2] = {1, 2};
+ const size_t size = 2;
+ EXPECT_EQ(ASessionCreationConfig_setTids(config, testTids, size), 0);
+ EXPECT_EQ(ASessionCreationConfig_setTargetWorkDurationNanos(config, 20), 0);
+ EXPECT_EQ(ASessionCreationConfig_setPreferPowerEfficiency(config, true), 0);
+ EXPECT_EQ(ASessionCreationConfig_setGraphicsPipeline(config, true), 0);
+ ASessionCreationConfig_release(config);
+}
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index 17459df..71f67d8 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -52,6 +52,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SessionCreationConfig;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -70,6 +71,7 @@
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
+import com.android.server.power.hint.HintManagerService.AppHintSession.SessionModes;
import com.android.server.utils.Slogf;
import java.io.FileDescriptor;
@@ -102,6 +104,8 @@
@VisibleForTesting final long mHintSessionPreferredRate;
+ @VisibleForTesting static final int MAX_GRAPHICS_PIPELINE_THREADS_COUNT = 5;
+
// Multi-level map storing all active AppHintSessions.
// First level is keyed by the UID of the client process creating the session.
// Second level is keyed by an IBinder passed from client process. This is used to observe
@@ -129,6 +133,14 @@
@GuardedBy("mSessionSnapshotMapLock")
private ArrayMap<Integer, ArrayMap<Integer, AppHintSessionSnapshot>> mSessionSnapshotMap;
+ /*
+ * App UID to Thread mapping.
+ * Thread is a sub class bookkeeping TID, thread mode (especially graphics pipeline mode)
+ * This is to bookkeep and track the thread usage.
+ */
+ @GuardedBy("mThreadsUsageObject")
+ private ArrayMap<Integer, ArraySet<ThreadUsageTracker>> mThreadsUsageMap;
+
/** Lock to protect mActiveSessions and the UidObserver. */
private final Object mLock = new Object();
@@ -144,6 +156,9 @@
*/
private final Object mSessionSnapshotMapLock = new Object();
+ /** Lock to protect mThreadsUsageMap. */
+ private final Object mThreadsUsageObject = new Object();
+
@GuardedBy("mNonIsolatedTidsLock")
private final Map<Integer, Set<Long>> mNonIsolatedTids;
@@ -262,6 +277,7 @@
mActiveSessions = new ArrayMap<>();
mChannelMap = new ArrayMap<>();
mSessionSnapshotMap = new ArrayMap<>();
+ mThreadsUsageMap = new ArrayMap<>();
mNativeWrapper = injector.createNativeWrapper();
mNativeWrapper.halInit();
mHintSessionPreferredRate = mNativeWrapper.halGetHintSessionPreferredRate();
@@ -357,6 +373,36 @@
}
}
+ private static class ThreadUsageTracker {
+ /*
+ * Thread object for tracking thread usage per UID
+ */
+ int mTid;
+ boolean mIsGraphicsPipeline;
+
+ ThreadUsageTracker(int tid) {
+ mTid = tid;
+ mIsGraphicsPipeline = false;
+ }
+
+ ThreadUsageTracker(int tid, boolean isGraphicsPipeline) {
+ mTid = tid;
+ mIsGraphicsPipeline = isGraphicsPipeline;
+ }
+
+ public int getTid() {
+ return mTid;
+ }
+
+ public boolean isGraphicsPipeline() {
+ return mIsGraphicsPipeline;
+ }
+
+ public void setGraphicsPipeline(boolean isGraphicsPipeline) {
+ mIsGraphicsPipeline = isGraphicsPipeline;
+ }
+ }
+
private class AppHintSessionSnapshot {
/*
* Per-Uid and Per-SessionTag snapshot that tracks metrics including
@@ -368,6 +414,7 @@
int mMaxConcurrentSession;
int mMaxThreadCount;
int mPowerEfficientSessionCount;
+ int mGraphicsPipelineSessionCount;
final int mTargetDurationNsCountPQSize = 100;
PriorityQueue<TargetDurationRecord> mTargetDurationNsCountPQ;
@@ -425,6 +472,7 @@
mMaxConcurrentSession = 0;
mMaxThreadCount = 0;
mPowerEfficientSessionCount = 0;
+ mGraphicsPipelineSessionCount = 0;
mTargetDurationNsCountPQ = new PriorityQueue<>(1);
}
@@ -443,6 +491,10 @@
mPowerEfficientSessionCount += 1;
}
+ void logGraphicsPipelineSession() {
+ mGraphicsPipelineSessionCount += 1;
+ }
+
void updateThreadCount(int threadCount) {
mMaxThreadCount = Math.max(mMaxThreadCount, threadCount);
}
@@ -473,6 +525,10 @@
return mPowerEfficientSessionCount;
}
+ int getGraphicsPipelineSessionCount() {
+ return mGraphicsPipelineSessionCount;
+ }
+
long[] targetDurationNsList() {
final int listSize = 5;
long[] targetDurations = new long[listSize];
@@ -1163,24 +1219,40 @@
+ " doesn't belong to the calling application " + callingUid;
}
+ private boolean contains(final int[] array, final int target) {
+ for (int element : array) {
+ if (element == target) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@VisibleForTesting
final class BinderService extends IHintManager.Stub {
@Override
public IHintSession createHintSessionWithConfig(@NonNull IBinder token,
- @NonNull int[] tids, long durationNanos, @SessionTag int tag,
- SessionConfig config) {
+ @SessionTag int tag, SessionCreationConfig creationConfig,
+ SessionConfig config) {
if (!isHalSupported()) {
throw new UnsupportedOperationException("PowerHAL is not supported!");
}
java.util.Objects.requireNonNull(token);
- java.util.Objects.requireNonNull(tids);
+ java.util.Objects.requireNonNull(creationConfig.tids);
+
+ final int[] tids = creationConfig.tids;
Preconditions.checkArgument(tids.length != 0, "tids should"
+ " not be empty.");
+
final int callingUid = Binder.getCallingUid();
final int callingTgid = Process.getThreadGroupLeader(Binder.getCallingPid());
final long identity = Binder.clearCallingIdentity();
+ final long durationNanos = creationConfig.targetWorkDurationNanos;
+
+ Preconditions.checkArgument(checkGraphicsPipelineValid(creationConfig, callingUid),
+ "not enough of available graphics pipeline thread.");
try {
final IntArray nonIsolated = powerhintThreadCleanup() ? new IntArray(tids.length)
: null;
@@ -1274,8 +1346,9 @@
.computeIfAbsent(tag, k -> new AppHintSessionSnapshot())
.updateUponSessionCreation(tids.length, durationNanos);
}
+ AppHintSession hs = null;
synchronized (mLock) {
- AppHintSession hs = new AppHintSession(callingUid, callingTgid, tag, tids,
+ hs = new AppHintSession(callingUid, callingTgid, tag, tids,
token, halSessionPtr, durationNanos);
ArrayMap<IBinder, ArraySet<AppHintSession>> tokenMap =
mActiveSessions.get(callingUid);
@@ -1290,9 +1363,29 @@
}
sessionSet.add(hs);
mUsesFmq = mUsesFmq || hasChannel(callingTgid, callingUid);
-
- return hs;
}
+
+ if (hs != null) {
+ boolean isGraphicsPipeline = false;
+ if (creationConfig.modesToEnable != null) {
+ for (int sessionMode : creationConfig.modesToEnable) {
+ if (sessionMode == SessionModes.GRAPHICS_PIPELINE.ordinal()) {
+ isGraphicsPipeline = true;
+ }
+ hs.setMode(sessionMode, true);
+ }
+ }
+
+ synchronized (mThreadsUsageObject) {
+ mThreadsUsageMap.computeIfAbsent(callingUid, k -> new ArraySet<>());
+ ArraySet<ThreadUsageTracker> threadsSet = mThreadsUsageMap.get(callingUid);
+ for (int i = 0; i < tids.length; ++i) {
+ threadsSet.add(new ThreadUsageTracker(tids[i], isGraphicsPipeline));
+ }
+ }
+ }
+
+ return hs;
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1335,6 +1428,11 @@
}
@Override
+ public int getMaxGraphicsPipelineThreadsCount() {
+ return MAX_GRAPHICS_PIPELINE_THREADS_COUNT;
+ }
+
+ @Override
public void setHintSessionThreads(@NonNull IHintSession hintSession, @NonNull int[] tids) {
AppHintSession appHintSession = (AppHintSession) hintSession;
appHintSession.setThreads(tids);
@@ -1470,6 +1568,7 @@
return;
}
pw.println("HintSessionPreferredRate: " + mHintSessionPreferredRate);
+ pw.println("MaxGraphicsPipelineThreadsCount: " + MAX_GRAPHICS_PIPELINE_THREADS_COUNT);
pw.println("HAL Support: " + isHalSupported());
pw.println("Active Sessions:");
synchronized (mLock) {
@@ -1507,6 +1606,45 @@
}
}
+ private boolean checkGraphicsPipelineValid(SessionCreationConfig creationConfig, int uid) {
+ if (creationConfig.modesToEnable == null) {
+ return true;
+ }
+ boolean setGraphicsPipeline = false;
+ for (int modeToEnable : creationConfig.modesToEnable) {
+ if (modeToEnable == SessionModes.GRAPHICS_PIPELINE.ordinal()) {
+ setGraphicsPipeline = true;
+ }
+ }
+ if (!setGraphicsPipeline) {
+ return true;
+ }
+
+ synchronized (mThreadsUsageObject) {
+ // count used graphics pipeline threads for the calling UID
+ // consider the case that new tids are overlapping with in session tids
+ ArraySet<ThreadUsageTracker> threadsSet = mThreadsUsageMap.get(uid);
+ if (threadsSet == null) {
+ return true;
+ }
+
+ final int newThreadCount = creationConfig.tids.length;
+ int graphicsPipelineThreadCount = 0;
+ for (ThreadUsageTracker t : threadsSet) {
+ // count graphics pipeline threads in use
+ // and exclude overlapping ones
+ if (t.isGraphicsPipeline()) {
+ graphicsPipelineThreadCount++;
+ if (contains(creationConfig.tids, t.getTid())) {
+ graphicsPipelineThreadCount--;
+ }
+ }
+ }
+ return graphicsPipelineThreadCount + newThreadCount
+ <= MAX_GRAPHICS_PIPELINE_THREADS_COUNT;
+ }
+ }
+
private void logPerformanceHintSessionAtom(int uid, long sessionId,
long targetDuration, int[] tids, @SessionTag int sessionTag) {
FrameworkStatsLog.write(FrameworkStatsLog.PERFORMANCE_HINT_SESSION_REPORTED, uid,
@@ -1537,11 +1675,14 @@
protected boolean mUpdateAllowedByProcState;
protected int[] mNewThreadIds;
protected boolean mPowerEfficient;
+ protected boolean mGraphicsPipeline;
protected boolean mHasBeenPowerEfficient;
+ protected boolean mHasBeenGraphicsPipeline;
protected boolean mShouldForcePause;
- private enum SessionModes {
+ enum SessionModes {
POWER_EFFICIENCY,
+ GRAPHICS_PIPELINE,
};
protected AppHintSession(
@@ -1556,7 +1697,9 @@
mTargetDurationNanos = durationNanos;
mUpdateAllowedByProcState = true;
mPowerEfficient = false;
+ mGraphicsPipeline = false;
mHasBeenPowerEfficient = false;
+ mHasBeenGraphicsPipeline = false;
mShouldForcePause = false;
final boolean allowed = mUidObserver.isUidForeground(mUid);
updateHintAllowedByProcState(allowed);
@@ -1677,6 +1820,25 @@
}
sessionSnapshot.updateUponSessionClose();
}
+
+ if (mGraphicsPipeline) {
+ synchronized (mThreadsUsageObject) {
+ ArraySet<ThreadUsageTracker> threadsSet = mThreadsUsageMap.get(mUid);
+ if (threadsSet == null) {
+ Slogf.w(TAG, "Threads Set is null for uid " + mUid);
+ return;
+ }
+ // remove all tids associated with this session
+ for (int i = 0; i < threadsSet.size(); ++i) {
+ if (contains(mThreadIds, threadsSet.valueAt(i).getTid())) {
+ threadsSet.removeAt(i);
+ }
+ }
+ if (threadsSet.isEmpty()) {
+ mThreadsUsageMap.remove(mUid);
+ }
+ }
+ }
if (powerhintThreadCleanup()) {
synchronized (mNonIsolatedTidsLock) {
final int[] tids = getTidsInternal();
@@ -1713,6 +1875,33 @@
throw new IllegalArgumentException("Thread id list can't be empty.");
}
+
+ final int callingUid = Binder.getCallingUid();
+ if (mGraphicsPipeline) {
+ synchronized (mThreadsUsageObject) {
+ // replace original tids with new tids
+ ArraySet<ThreadUsageTracker> threadsSet = mThreadsUsageMap.get(callingUid);
+ int graphicsPipelineThreadCount = 0;
+ if (threadsSet != null) {
+ // We count the graphics pipeline threads that are
+ // *not* in this session, since those in this session
+ // will be replaced. Then if the count plus the new tids
+ // is over max available graphics pipeline threads we raise
+ // an exception.
+ for (ThreadUsageTracker t : threadsSet) {
+ if (t.isGraphicsPipeline() && !contains(mThreadIds, t.getTid())) {
+ graphicsPipelineThreadCount++;
+ }
+ }
+ if (graphicsPipelineThreadCount + tids.length
+ > MAX_GRAPHICS_PIPELINE_THREADS_COUNT) {
+ throw new IllegalArgumentException(
+ "Not enough available graphics pipeline threads.");
+ }
+ }
+ }
+ }
+
synchronized (this) {
if (mHalSessionPtr == 0) {
return;
@@ -1724,7 +1913,6 @@
return;
}
if (checkTid) {
- final int callingUid = Binder.getCallingUid();
final int callingTgid = Process.getThreadGroupLeader(Binder.getCallingPid());
final IntArray nonIsolated = powerhintThreadCleanup() ? new IntArray() : null;
final long identity = Binder.clearCallingIdentity();
@@ -1770,6 +1958,23 @@
}
}
mNativeWrapper.halSetThreads(mHalSessionPtr, tids);
+
+ synchronized (mThreadsUsageObject) {
+ // replace old tids with new ones
+ ArraySet<ThreadUsageTracker> threadsSet = mThreadsUsageMap.get(callingUid);
+ if (threadsSet == null) {
+ mThreadsUsageMap.put(callingUid, new ArraySet<ThreadUsageTracker>());
+ threadsSet = mThreadsUsageMap.get(callingUid);
+ }
+ for (int i = 0; i < threadsSet.size(); ++i) {
+ if (contains(mThreadIds, threadsSet.valueAt(i).getTid())) {
+ threadsSet.removeAt(i);
+ }
+ }
+ for (int tid : tids) {
+ threadsSet.add(new ThreadUsageTracker(tid, mGraphicsPipeline));
+ }
+ }
mThreadIds = tids;
mNewThreadIds = null;
// if the update is allowed but the session is force paused by tid clean up, then
@@ -1831,26 +2036,49 @@
+ " greater than zero.");
if (mode == SessionModes.POWER_EFFICIENCY.ordinal()) {
mPowerEfficient = enabled;
+ } else if (mode == SessionModes.GRAPHICS_PIPELINE.ordinal()) {
+ mGraphicsPipeline = enabled;
}
mNativeWrapper.halSetMode(mHalSessionPtr, mode, enabled);
}
- if (enabled && (mode == SessionModes.POWER_EFFICIENCY.ordinal())) {
- if (!mHasBeenPowerEfficient) {
- mHasBeenPowerEfficient = true;
- synchronized (mSessionSnapshotMapLock) {
- ArrayMap<Integer, AppHintSessionSnapshot> sessionSnapshots =
- mSessionSnapshotMap.get(mUid);
- if (sessionSnapshots == null) {
- Slogf.w(TAG, "Session snapshot map is null for uid " + mUid);
- return;
+ if (enabled) {
+ if (mode == SessionModes.POWER_EFFICIENCY.ordinal()) {
+ if (!mHasBeenPowerEfficient) {
+ mHasBeenPowerEfficient = true;
+ synchronized (mSessionSnapshotMapLock) {
+ ArrayMap<Integer, AppHintSessionSnapshot> sessionSnapshots =
+ mSessionSnapshotMap.get(mUid);
+ if (sessionSnapshots == null) {
+ Slogf.w(TAG, "Session snapshot map is null for uid " + mUid);
+ return;
+ }
+ AppHintSessionSnapshot sessionSnapshot = sessionSnapshots.get(mTag);
+ if (sessionSnapshot == null) {
+ Slogf.w(TAG, "Session snapshot is null for uid " + mUid
+ + " and tag " + mTag);
+ return;
+ }
+ sessionSnapshot.logPowerEfficientSession();
}
- AppHintSessionSnapshot sessionSnapshot = sessionSnapshots.get(mTag);
- if (sessionSnapshot == null) {
- Slogf.w(TAG, "Session snapshot is null for uid " + mUid
- + " and tag " + mTag);
- return;
+ }
+ } else if (mode == SessionModes.GRAPHICS_PIPELINE.ordinal()) {
+ if (!mHasBeenGraphicsPipeline) {
+ mHasBeenGraphicsPipeline = true;
+ synchronized (mSessionSnapshotMapLock) {
+ ArrayMap<Integer, AppHintSessionSnapshot> sessionSnapshots =
+ mSessionSnapshotMap.get(mUid);
+ if (sessionSnapshots == null) {
+ Slogf.w(TAG, "Session snapshot map is null for uid " + mUid);
+ return;
+ }
+ AppHintSessionSnapshot sessionSnapshot = sessionSnapshots.get(mTag);
+ if (sessionSnapshot == null) {
+ Slogf.w(TAG, "Session snapshot is null for uid " + mUid
+ + " and tag " + mTag);
+ return;
+ }
+ sessionSnapshot.logGraphicsPipelineSession();
}
- sessionSnapshot.logPowerEfficientSession();
}
}
}
@@ -1877,6 +2105,12 @@
}
}
+ public boolean isGraphicsPipeline() {
+ synchronized (this) {
+ return mGraphicsPipeline;
+ }
+ }
+
public int getUid() {
return mUid;
}
@@ -1964,6 +2198,7 @@
pw.println(prefix + "SessionAllowedByProcState: " + mUpdateAllowedByProcState);
pw.println(prefix + "SessionForcePaused: " + mShouldForcePause);
pw.println(prefix + "PowerEfficient: " + (mPowerEfficient ? "true" : "false"));
+ pw.println(prefix + "GraphicsPipeline: " + (mGraphicsPipeline ? "true" : "false"));
}
}
diff --git a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
index 0881b4c..e631cb6 100644
--- a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
+++ b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
@@ -66,6 +66,7 @@
import android.os.PerformanceHintManager;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SessionCreationConfig;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -200,7 +201,7 @@
when(mNativeWrapperMock.halCreateHintSessionWithConfig(eq(TGID), eq(UID),
eq(SESSION_TIDS_C), eq(0L), anyInt(),
any(SessionConfig.class))).thenAnswer(fakeCreateWithConfig(SESSION_PTRS[2],
- SESSION_IDS[2]));
+ SESSION_IDS[2]));
when(mIPowerMock.getInterfaceVersion()).thenReturn(6);
when(mIPowerMock.getSessionChannel(anyInt(), anyInt())).thenReturn(mConfig);
@@ -305,6 +306,14 @@
return mService;
}
+ private SessionCreationConfig makeSessionCreationConfig(int[] tids,
+ long targetWorkDurationNanos) {
+ SessionCreationConfig config = new SessionCreationConfig();
+ config.tids = tids;
+ config.targetWorkDurationNanos = targetWorkDurationNanos;
+ return config;
+ }
+
@Test
public void testInitializeService() {
HintManagerService service = createService();
@@ -316,12 +325,14 @@
public void testCreateHintSessionInvalidPid() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(new int[]{TID, 1}, DEFAULT_TARGET_DURATION);
// Make sure we throw exception when adding a TID doesn't belong to the processes
// In this case, we add `init` PID into the list.
SessionConfig config = new SessionConfig();
assertThrows(SecurityException.class,
() -> service.getBinderServiceInstance().createHintSessionWithConfig(token,
- new int[]{TID, 1}, DEFAULT_TARGET_DURATION, SessionTag.OTHER, config));
+ SessionTag.OTHER, creationConfig, config));
}
@Test
@@ -329,17 +340,23 @@
HintManagerService service = createService();
IBinder token = new Binder();
makeConfigCreationUnsupported();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
IHintSession a = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SESSION_TIDS_A, DEFAULT_TARGET_DURATION, SessionTag.OTHER, new SessionConfig());
+ SessionTag.OTHER, creationConfig, new SessionConfig());
assertNotNull(a);
+ creationConfig.tids = SESSION_TIDS_B;
+ creationConfig.targetWorkDurationNanos = DOUBLED_TARGET_DURATION;
IHintSession b = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SESSION_TIDS_B, DOUBLED_TARGET_DURATION, SessionTag.OTHER, new SessionConfig());
+ SessionTag.OTHER, creationConfig, new SessionConfig());
assertNotEquals(a, b);
+ creationConfig.tids = SESSION_TIDS_C;
+ creationConfig.targetWorkDurationNanos = 0L;
IHintSession c = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SESSION_TIDS_C, 0L, SessionTag.OTHER, new SessionConfig());
+ SessionTag.OTHER, creationConfig, new SessionConfig());
assertNotNull(c);
verify(mNativeWrapperMock, times(3)).halCreateHintSession(anyInt(), anyInt(),
any(int[].class), anyLong());
@@ -349,22 +366,28 @@
public void testCreateHintSessionWithConfig() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
SessionConfig config = new SessionConfig();
IHintSession a = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SESSION_TIDS_A, DEFAULT_TARGET_DURATION, SessionTag.OTHER, config);
+ SessionTag.OTHER, creationConfig, config);
assertNotNull(a);
assertEquals(SESSION_IDS[0], config.id);
SessionConfig config2 = new SessionConfig();
+ creationConfig.tids = SESSION_TIDS_B;
+ creationConfig.targetWorkDurationNanos = DOUBLED_TARGET_DURATION;
IHintSession b = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SESSION_TIDS_B, DOUBLED_TARGET_DURATION, SessionTag.APP, config2);
+ SessionTag.APP, creationConfig, config2);
assertNotEquals(a, b);
assertEquals(SESSION_IDS[1], config2.id);
SessionConfig config3 = new SessionConfig();
+ creationConfig.tids = SESSION_TIDS_C;
+ creationConfig.targetWorkDurationNanos = 0L;
IHintSession c = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SESSION_TIDS_C, 0L, SessionTag.GAME, config3);
+ SessionTag.GAME, creationConfig, config3);
assertNotNull(c);
assertEquals(SESSION_IDS[2], config3.id);
verify(mNativeWrapperMock, times(3)).halCreateHintSessionWithConfig(anyInt(), anyInt(),
@@ -372,13 +395,48 @@
}
@Test
- public void testPauseResumeHintSession() throws Exception {
+ public void testCreateGraphicsPipelineSessions() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ final int threadCount =
+ service.getBinderServiceInstance().getMaxGraphicsPipelineThreadsCount();
+ long sessionPtr1 = 1111L;
+ long sessionId1 = 11111L;
+ CountDownLatch stopLatch1 = new CountDownLatch(1);
+ int[] tids1 = createThreads(threadCount, stopLatch1);
+ when(mNativeWrapperMock.halCreateHintSessionWithConfig(eq(TGID), eq(UID), eq(tids1),
+ eq(DEFAULT_TARGET_DURATION), anyInt(), any(SessionConfig.class)))
+ .thenAnswer(fakeCreateWithConfig(sessionPtr1, sessionId1));
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(tids1, DEFAULT_TARGET_DURATION);
+
+ creationConfig.modesToEnable = new int[] {1}; // GRAPHICS_PIPELINE
+
+ SessionConfig config = new SessionConfig();
+ IHintSession a = service.getBinderServiceInstance().createHintSessionWithConfig(token,
+ SessionTag.OTHER, creationConfig, config);
+ assertNotNull(a);
+ assertEquals(sessionId1, config.id);
+
+ creationConfig.tids = createThreads(1, stopLatch1);
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ service.getBinderServiceInstance().createHintSessionWithConfig(token,
+ SessionTag.OTHER, creationConfig, config);
+ });
+ }
+
+ @Test
+ public void testPauseResumeHintSession() throws Exception {
+ HintManagerService service = createService();
+ IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
+
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
// Set session to background and calling updateHintAllowedByProcState() would invoke
// pause();
@@ -414,9 +472,11 @@
public void testCloseHintSession() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
IHintSession a = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SESSION_TIDS_A, DEFAULT_TARGET_DURATION, SessionTag.OTHER, new SessionConfig());
+ SessionTag.OTHER, creationConfig, new SessionConfig());
a.close();
verify(mNativeWrapperMock, times(1)).halCloseHintSession(anyLong());
@@ -426,9 +486,11 @@
public void testUpdateTargetWorkDuration() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
IHintSession a = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SESSION_TIDS_A, DEFAULT_TARGET_DURATION, SessionTag.OTHER, new SessionConfig());
+ SessionTag.OTHER, creationConfig, new SessionConfig());
assertThrows(IllegalArgumentException.class, () -> {
a.updateTargetWorkDuration(-1L);
@@ -446,10 +508,12 @@
public void testReportActualWorkDuration() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
a.updateTargetWorkDuration(100L);
a.reportActualWorkDuration(DURATIONS_THREE, TIMESTAMPS_THREE);
@@ -489,10 +553,12 @@
public void testSendHint() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
a.sendHint(PerformanceHintManager.Session.CPU_LOAD_RESET);
verify(mNativeWrapperMock, times(1)).halSendHint(anyLong(),
@@ -516,10 +582,12 @@
public void testDoHintInBackground() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
service.mUidObserver.onUidStateChanged(
a.mUid, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND, 0, 0);
@@ -538,10 +606,12 @@
public void testDoHintInForeground() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
service.mUidObserver.onUidStateChanged(
a.mUid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0, 0);
@@ -552,10 +622,12 @@
public void testSetThreads() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
a.updateTargetWorkDuration(100L);
@@ -591,9 +663,11 @@
when(mNativeWrapperMock.halCreateHintSessionWithConfig(eq(TGID), eq(UID), eq(tids1),
eq(DEFAULT_TARGET_DURATION), anyInt(), any(SessionConfig.class)))
.thenReturn(sessionPtr1);
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(tids1, DEFAULT_TARGET_DURATION);
AppHintSession session1 = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, tids1, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
assertNotNull(session1);
// trigger UID state change by making the process foreground->background, but because the
@@ -626,9 +700,11 @@
when(mNativeWrapperMock.halCreateHintSessionWithConfig(eq(TGID), eq(UID), eq(tids1),
eq(DEFAULT_TARGET_DURATION), anyInt(), any(SessionConfig.class)))
.thenReturn(sessionPtr1);
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(tids1, DEFAULT_TARGET_DURATION);
AppHintSession session1 = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, tids1, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
assertNotNull(session1);
// let all session 1 threads to exit and the cleanup should force pause the session 1
@@ -734,10 +810,12 @@
public void testSetMode() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
a.setMode(0, true);
verify(mNativeWrapperMock, times(1)).halSetMode(anyLong(),
@@ -746,12 +824,19 @@
a.setMode(0, false);
verify(mNativeWrapperMock, times(1)).halSetMode(anyLong(),
eq(0), eq(false));
+ }
- assertThrows(IllegalArgumentException.class, () -> {
- a.setMode(-1, true);
- });
+ @Test
+ public void testSetModeSessionInBackGround() throws Exception {
+ HintManagerService service = createService();
+ IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
- reset(mNativeWrapperMock);
+ AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
+
// Set session to background, then the duration would not be updated.
service.mUidObserver.onUidStateChanged(
a.mUid, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
@@ -763,6 +848,40 @@
}
@Test
+ public void testSetModeInvalid() throws Exception {
+ HintManagerService service = createService();
+ IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
+
+ AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ a.setMode(-1, true);
+ });
+ }
+
+ @Test
+ public void testSetModeUponSessionCreation() throws Exception {
+ HintManagerService service = createService();
+ IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
+ creationConfig.modesToEnable = new int[] {0, 1};
+
+ AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
+ assertNotNull(a);
+ verify(mNativeWrapperMock, times(1)).halSetMode(anyLong(),
+ eq(0), eq(true));
+ verify(mNativeWrapperMock, times(1)).halSetMode(anyLong(),
+ eq(1), eq(true));
+ }
+
+ @Test
public void testGetChannel() throws Exception {
HintManagerService service = createService();
Binder token = new Binder();
@@ -950,9 +1069,12 @@
private void runAppHintSession(HintManagerService service, int logId,
AtomicReference<Boolean> shouldRun) throws Exception {
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
+
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
// we will start some threads and get their valid TIDs to update
int threadCount = 3;
// the list of TIDs
@@ -1017,10 +1139,12 @@
public void testReportActualWorkDuration2() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
+ SessionCreationConfig creationConfig =
+ makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
- .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
- SessionTag.OTHER, new SessionConfig());
+ .createHintSessionWithConfig(token, SessionTag.OTHER,
+ creationConfig, new SessionConfig());
a.updateTargetWorkDuration(100L);
a.reportActualWorkDuration2(WORK_DURATIONS_FIVE);