Add plumbing for ADPF Power Efficiency hint
These patches introduce a new power efficiency mode for hint sessions
to the public API, and internally expose a new setMode API for hint
sessions that resembles the setMode API for iPower, to control
different session operating modes.
This set of patches:
- Updates the PowerHAL AIDL to version 5, and updates relevant bp files
- Exposes new setPreferPowerEfficiency(bool enabled) method from the
SDK and NDK
- Exposes new setMode(int mode, bool enabled) method from PowerHAL AIDL
and HintManagerService
- Adds support for new setMode call in PowerHAL
Bug: b/288117936
Test: atest cts/tests/tests/os/src/android/os/cts/PerformanceHintManagerTest.java
Test: atest HintManagerServiceTest
Change-Id: Ia1349e1bd8c4c85276788892b69897b5ef267c03
diff --git a/core/api/current.txt b/core/api/current.txt
index 0b10d64..9e81bb1 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -33662,6 +33662,7 @@
public static class PerformanceHintManager.Session implements java.io.Closeable {
method public void close();
method public void reportActualWorkDuration(long);
+ method public void setPreferPowerEfficiency(boolean);
method public void setThreads(@NonNull int[]);
method public void updateTargetWorkDuration(long);
}
diff --git a/core/java/android/os/IHintSession.aidl b/core/java/android/os/IHintSession.aidl
index 0d1dde1..6b43e73 100644
--- a/core/java/android/os/IHintSession.aidl
+++ b/core/java/android/os/IHintSession.aidl
@@ -23,4 +23,5 @@
void reportActualWorkDuration(in long[] actualDurationNanos, in long[] timeStampNanos);
void close();
void sendHint(int hint);
+ void setMode(int mode, boolean enabled);
}
diff --git a/core/java/android/os/PerformanceHintManager.java b/core/java/android/os/PerformanceHintManager.java
index bcea797..cbc9213 100644
--- a/core/java/android/os/PerformanceHintManager.java
+++ b/core/java/android/os/PerformanceHintManager.java
@@ -51,6 +51,15 @@
}
/**
+ * Get preferred update rate information for this device.
+ *
+ * @return the preferred update rate supported by device software
+ */
+ public long getPreferredUpdateRateNanos() {
+ return nativeGetPreferredUpdateRateNanos(mNativeManagerPtr);
+ }
+
+ /**
* Creates a {@link Session} for the given set of threads and sets their initial target work
* duration.
*
@@ -78,35 +87,22 @@
}
/**
- * Get preferred update rate information for this device.
- *
- * @return the preferred update rate supported by device software
- */
- public long getPreferredUpdateRateNanos() {
- return nativeGetPreferredUpdateRateNanos(mNativeManagerPtr);
- }
-
- /**
* A Session represents a group of threads with an inter-related workload such that hints for
* their performance should be considered as a unit. The threads in a given session should be
- * long-life and not created or destroyed dynamically.
+ * long-lived and not created or destroyed dynamically.
*
- * <p>Each session is expected to have a periodic workload with a target duration for each
- * cycle. The cycle duration is likely greater than the target work duration to allow other
- * parts of the pipeline to run within the available budget. For example, a renderer thread may
- * work at 60hz in order to produce frames at the display's frame but have a target work
- * duration of only 6ms.</p>
+ * The work duration API can be used with periodic workloads to dynamically adjust thread
+ * performance and keep the work on schedule while optimizing the available power budget.
+ * When using the work duration API, the starting target duration should be specified
+ * while creating the session, but can later be adjusted with
+ * {@link #updateTargetWorkDuration(long)}. While using the work duration API, the client is be
+ * expected to call {@link #reportActualWorkDuration(long)} each cycle to report the actual
+ * time taken to complete to the system.
*
- * <p>Any call in this class will change its internal data, so you must do your own thread
- * safety to protect from racing.</p>
+ * Any call in this class will change its internal data, so you must do your own thread
+ * safety to protect from racing.
*
- * <p>Note that the target work duration can be {@link #updateTargetWorkDuration(long) updated}
- * if workloads change.</p>
- *
- * <p>After each cycle of work, the client is expected to
- * {@link #reportActualWorkDuration(long) report} the actual time taken to complete.</p>
- *
- * <p>All timings should be in {@link SystemClock#elapsedRealtimeNanos()}.</p>
+ * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}.
*/
public static class Session implements Closeable {
private long mNativeSessionPtr;
@@ -186,9 +182,9 @@
/**
* Reports the actual duration for the last cycle of work.
*
- * <p>The system will attempt to adjust the core placement of the threads within the thread
+ * The system will attempt to adjust the core placement of the threads within the thread
* group and/or the frequency of the core on which they are run to bring the actual duration
- * close to the target duration.</p>
+ * close to the target duration.
*
* @param actualDurationNanos how long the thread group took to complete its last task in
* nanoseconds
@@ -202,7 +198,7 @@
/**
* Ends the current hint session.
*
- * <p>Once called, you should not call anything else on this object.</p>
+ * Once called, you should not call anything else on this object.
*/
public void close() {
if (mNativeSessionPtr != 0) {
@@ -230,6 +226,16 @@
}
/**
+ * This tells the session that these threads can be
+ * safely scheduled to prefer power efficiency over performance.
+ *
+ * @param enabled The flag that sets whether this session uses power-efficient scheduling.
+ */
+ public void setPreferPowerEfficiency(boolean enabled) {
+ nativeSetPreferPowerEfficiency(mNativeSessionPtr, enabled);
+ }
+
+ /**
* Set a list of threads to the performance hint session. This operation will replace
* the current list of threads with the given list of threads.
* Note that this is not an oneway method.
@@ -275,4 +281,6 @@
private static native void nativeCloseSession(long nativeSessionPtr);
private static native void nativeSendHint(long nativeSessionPtr, int hint);
private static native void nativeSetThreads(long nativeSessionPtr, int[] tids);
+ private static native void nativeSetPreferPowerEfficiency(long nativeSessionPtr,
+ boolean enabled);
}
diff --git a/core/jni/android_os_PerformanceHintManager.cpp b/core/jni/android_os_PerformanceHintManager.cpp
index ffe844d..27c4cd4 100644
--- a/core/jni/android_os_PerformanceHintManager.cpp
+++ b/core/jni/android_os_PerformanceHintManager.cpp
@@ -34,26 +34,28 @@
struct APerformanceHintSession;
typedef APerformanceHintManager* (*APH_getManager)();
+typedef int64_t (*APH_getPreferredUpdateRateNanos)(APerformanceHintManager* manager);
typedef APerformanceHintSession* (*APH_createSession)(APerformanceHintManager*, const int32_t*,
size_t, int64_t);
-typedef int64_t (*APH_getPreferredUpdateRateNanos)(APerformanceHintManager* manager);
typedef void (*APH_updateTargetWorkDuration)(APerformanceHintSession*, int64_t);
typedef void (*APH_reportActualWorkDuration)(APerformanceHintSession*, int64_t);
typedef void (*APH_closeSession)(APerformanceHintSession* session);
typedef void (*APH_sendHint)(APerformanceHintSession*, int32_t);
typedef int (*APH_setThreads)(APerformanceHintSession*, const pid_t*, size_t);
typedef void (*APH_getThreadIds)(APerformanceHintSession*, int32_t* const, size_t* const);
+typedef void (*APH_setPreferPowerEfficiency)(APerformanceHintSession*, bool);
bool gAPerformanceHintBindingInitialized = false;
APH_getManager gAPH_getManagerFn = nullptr;
-APH_createSession gAPH_createSessionFn = nullptr;
APH_getPreferredUpdateRateNanos gAPH_getPreferredUpdateRateNanosFn = nullptr;
+APH_createSession gAPH_createSessionFn = nullptr;
APH_updateTargetWorkDuration gAPH_updateTargetWorkDurationFn = nullptr;
APH_reportActualWorkDuration gAPH_reportActualWorkDurationFn = nullptr;
APH_closeSession gAPH_closeSessionFn = nullptr;
APH_sendHint gAPH_sendHintFn = nullptr;
APH_setThreads gAPH_setThreadsFn = nullptr;
APH_getThreadIds gAPH_getThreadIdsFn = nullptr;
+APH_setPreferPowerEfficiency gAPH_setPreferPowerEfficiencyFn = nullptr;
void ensureAPerformanceHintBindingInitialized() {
if (gAPerformanceHintBindingInitialized) return;
@@ -65,10 +67,6 @@
LOG_ALWAYS_FATAL_IF(gAPH_getManagerFn == nullptr,
"Failed to find required symbol APerformanceHint_getManager!");
- gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession");
- LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr,
- "Failed to find required symbol APerformanceHint_createSession!");
-
gAPH_getPreferredUpdateRateNanosFn =
(APH_getPreferredUpdateRateNanos)dlsym(handle_,
"APerformanceHint_getPreferredUpdateRateNanos");
@@ -76,6 +74,10 @@
"Failed to find required symbol "
"APerformanceHint_getPreferredUpdateRateNanos!");
+ gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession");
+ LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr,
+ "Failed to find required symbol APerformanceHint_createSession!");
+
gAPH_updateTargetWorkDurationFn =
(APH_updateTargetWorkDuration)dlsym(handle_,
"APerformanceHint_updateTargetWorkDuration");
@@ -96,8 +98,7 @@
gAPH_sendHintFn = (APH_sendHint)dlsym(handle_, "APerformanceHint_sendHint");
LOG_ALWAYS_FATAL_IF(gAPH_sendHintFn == nullptr,
- "Failed to find required symbol "
- "APerformanceHint_sendHint!");
+ "Failed to find required symbol APerformanceHint_sendHint!");
gAPH_setThreadsFn = (APH_setThreads)dlsym(handle_, "APerformanceHint_setThreads");
LOG_ALWAYS_FATAL_IF(gAPH_setThreadsFn == nullptr,
@@ -107,6 +108,13 @@
LOG_ALWAYS_FATAL_IF(gAPH_getThreadIdsFn == nullptr,
"Failed to find required symbol APerformanceHint_getThreadIds!");
+ gAPH_setPreferPowerEfficiencyFn =
+ (APH_setPreferPowerEfficiency)dlsym(handle_,
+ "APerformanceHint_setPreferPowerEfficiency");
+ LOG_ALWAYS_FATAL_IF(gAPH_setPreferPowerEfficiencyFn == nullptr,
+ "Failed to find required symbol"
+ "APerformanceHint_setPreferPowerEfficiency!");
+
gAPerformanceHintBindingInitialized = true;
}
@@ -223,6 +231,13 @@
return jintArr;
}
+static void nativeSetPreferPowerEfficiency(JNIEnv* env, jclass clazz, jlong nativeSessionPtr,
+ jboolean enabled) {
+ ensureAPerformanceHintBindingInitialized();
+ gAPH_setPreferPowerEfficiencyFn(reinterpret_cast<APerformanceHintSession*>(nativeSessionPtr),
+ enabled);
+}
+
static const JNINativeMethod gPerformanceHintMethods[] = {
{"nativeAcquireManager", "()J", (void*)nativeAcquireManager},
{"nativeGetPreferredUpdateRateNanos", "(J)J", (void*)nativeGetPreferredUpdateRateNanos},
@@ -233,6 +248,7 @@
{"nativeSendHint", "(JI)V", (void*)nativeSendHint},
{"nativeSetThreads", "(J[I)V", (void*)nativeSetThreads},
{"nativeGetThreadIds", "(J)[I", (void*)nativeGetThreadIds},
+ {"nativeSetPreferPowerEfficiency", "(JZ)V", (void*)nativeSetPreferPowerEfficiency},
};
int register_android_os_PerformanceHintManager(JNIEnv* env) {
diff --git a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
index b0826ab..20ba427 100644
--- a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
+++ b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
@@ -173,4 +173,13 @@
session.setThreads(new int[]{-1});
});
}
+
+ @Test
+ public void testSetPreferPowerEfficiency() {
+ Session s = createSession();
+ assumeNotNull(s);
+ s.setPreferPowerEfficiency(false);
+ s.setPreferPowerEfficiency(true);
+ s.setPreferPowerEfficiency(true);
+ }
}
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 254eb44..7f3792d 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -46,7 +46,10 @@
cc_library_shared {
name: "libandroid",
- defaults: ["libandroid_defaults"],
+ defaults: [
+ "libandroid_defaults",
+ "android.hardware.power-ndk_shared",
+ ],
srcs: [
"activity_manager.cpp",
@@ -95,7 +98,6 @@
"libpowermanager",
"android.hardware.configstore@1.0",
"android.hardware.configstore-utils",
- "android.hardware.power-V4-ndk",
"libnativedisplay",
],
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index d74f9b7..b0af09c 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -334,6 +334,7 @@
APerformanceHint_reportActualWorkDuration; # introduced=Tiramisu
APerformanceHint_closeSession; # introduced=Tiramisu
APerformanceHint_setThreads; # introduced=UpsideDownCake
+ APerformanceHint_setPreferPowerEfficiency; # introduced=VanillaIceCream
local:
*;
};
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index 6198f40..c25df6e 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "perf_hint"
#include <aidl/android/hardware/power/SessionHint.h>
+#include <aidl/android/hardware/power/SessionMode.h>
#include <android/os/IHintManager.h>
#include <android/os/IHintSession.h>
#include <android/performance_hint.h>
@@ -36,6 +37,7 @@
using namespace std::chrono_literals;
using AidlSessionHint = aidl::android::hardware::power::SessionHint;
+using AidlSessionMode = aidl::android::hardware::power::SessionMode;
struct APerformanceHintSession;
@@ -72,6 +74,7 @@
int sendHint(SessionHint hint);
int setThreads(const int32_t* threadIds, size_t size);
int getThreadIds(int32_t* const threadIds, size_t* size);
+ int setPreferPowerEfficiency(bool enabled);
private:
friend struct APerformanceHintManager;
@@ -307,6 +310,18 @@
return 0;
}
+int APerformanceHintSession::setPreferPowerEfficiency(bool enabled) {
+ binder::Status ret =
+ mHintSession->setMode(static_cast<int32_t>(AidlSessionMode::POWER_EFFICIENCY), enabled);
+
+ if (!ret.isOk()) {
+ ALOGE("%s: HintSession setPreferPowerEfficiency failed: %s", __FUNCTION__,
+ ret.exceptionMessage().c_str());
+ return EPIPE;
+ }
+ return OK;
+}
+
// ===================================== C API
APerformanceHintManager* APerformanceHint_getManager() {
return APerformanceHintManager::getInstance();
@@ -357,6 +372,10 @@
->getThreadIds(threadIds, size);
}
+int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) {
+ return session->setPreferPowerEfficiency(enabled);
+}
+
void APerformanceHint_setIHintManagerForTesting(void* iManager) {
delete gHintManagerForTesting;
gHintManagerForTesting = nullptr;
diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
index 6f7562b..22d33b1 100644
--- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
+++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
@@ -56,7 +56,8 @@
(const ::std::vector<int64_t>& actualDurationNanos,
const ::std::vector<int64_t>& timeStampNanos),
(override));
- MOCK_METHOD(Status, sendHint, (int32_t hints), (override));
+ MOCK_METHOD(Status, sendHint, (int32_t hint), (override));
+ MOCK_METHOD(Status, setMode, (int32_t mode, bool enabled), (override));
MOCK_METHOD(Status, close, (), (override));
MOCK_METHOD(IBinder*, onAsBinder, (), (override));
};
@@ -190,3 +191,51 @@
result = APerformanceHint_setThreads(session, invalidTids.data(), invalidTids.size());
EXPECT_EQ(EPERM, result);
}
+
+TEST_F(PerformanceHintTest, SetPowerEfficient) {
+ APerformanceHintManager* manager = createManager();
+
+ std::vector<int32_t> tids;
+ tids.push_back(1);
+ tids.push_back(2);
+ int64_t targetDuration = 56789L;
+
+ StrictMock<MockIHintSession>* iSession = new StrictMock<MockIHintSession>();
+ sp<IHintSession> session_sp(iSession);
+
+ EXPECT_CALL(*mMockIHintManager, createHintSession(_, Eq(tids), Eq(targetDuration), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(std::move(session_sp)), Return(Status())));
+
+ APerformanceHintSession* session =
+ APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration);
+ ASSERT_TRUE(session);
+
+ EXPECT_CALL(*iSession, setMode(_, Eq(true))).Times(Exactly(1));
+ int result = APerformanceHint_setPreferPowerEfficiency(session, true);
+ EXPECT_EQ(0, result);
+
+ EXPECT_CALL(*iSession, setMode(_, Eq(false))).Times(Exactly(1));
+ result = APerformanceHint_setPreferPowerEfficiency(session, false);
+ EXPECT_EQ(0, result);
+}
+
+TEST_F(PerformanceHintTest, CreateZeroTargetDurationSession) {
+ APerformanceHintManager* manager = createManager();
+
+ std::vector<int32_t> tids;
+ tids.push_back(1);
+ tids.push_back(2);
+ int64_t targetDuration = 0;
+
+ StrictMock<MockIHintSession>* iSession = new StrictMock<MockIHintSession>();
+ sp<IHintSession> session_sp(iSession);
+
+ EXPECT_CALL(*mMockIHintManager, createHintSession(_, Eq(tids), Eq(targetDuration), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(std::move(session_sp)), Return(Status())));
+
+ APerformanceHintSession* session =
+ APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration);
+ ASSERT_TRUE(session);
+}
\ No newline at end of file
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 9f263c8..c2774e5 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -98,7 +98,10 @@
java_library_static {
name: "services.core.unboosted",
- defaults: ["platform_service_defaults"],
+ defaults: [
+ "platform_service_defaults",
+ "android.hardware.power-java_static",
+ ],
srcs: [
":android.hardware.biometrics.face-V3-java-source",
":android.hardware.tv.hdmi.connection-V1-java-source",
@@ -152,7 +155,7 @@
"android.hardware.boot-V1.0-java", // HIDL
"android.hardware.boot-V1.1-java", // HIDL
"android.hardware.boot-V1.2-java", // HIDL
- "android.hardware.boot-V1-java", // AIDL
+ "android.hardware.boot-V1-java", // AIDL
"android.hardware.broadcastradio-V2.0-java", // HIDL
"android.hardware.broadcastradio-V1-java", // AIDL
"android.hardware.health-V1.0-java", // HIDL
@@ -176,7 +179,6 @@
"android.hardware.ir-V1-java",
"android.hardware.rebootescrow-V1-java",
"android.hardware.power.stats-V2-java",
- "android.hardware.power-V4-java",
"android.hidl.manager-V1.2-java",
"cbor-java",
"icu4j_calendar_astronomer",
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 8dcf3e0..33bed3d 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -171,6 +171,8 @@
public static class NativeWrapper {
private native void nativeInit();
+ private static native long nativeGetHintSessionPreferredRate();
+
private static native long nativeCreateHintSession(int tgid, int uid, int[] tids,
long durationNanos);
@@ -190,13 +192,18 @@
private static native void nativeSetThreads(long halPtr, int[] tids);
- private static native long nativeGetHintSessionPreferredRate();
+ private static native void nativeSetMode(long halPtr, int mode, boolean enabled);
/** Wrapper for HintManager.nativeInit */
public void halInit() {
nativeInit();
}
+ /** Wrapper for HintManager.nativeGetHintSessionPreferredRate */
+ public long halGetHintSessionPreferredRate() {
+ return nativeGetHintSessionPreferredRate();
+ }
+
/** Wrapper for HintManager.nativeCreateHintSession */
public long halCreateHintSession(int tgid, int uid, int[] tids, long durationNanos) {
return nativeCreateHintSession(tgid, uid, tids, durationNanos);
@@ -234,15 +241,16 @@
nativeSendHint(halPtr, hint);
}
- /** Wrapper for HintManager.nativeGetHintSessionPreferredRate */
- public long halGetHintSessionPreferredRate() {
- return nativeGetHintSessionPreferredRate();
- }
-
/** Wrapper for HintManager.nativeSetThreads */
public void halSetThreads(long halPtr, int[] tids) {
nativeSetThreads(halPtr, tids);
}
+
+ /** Wrapper for HintManager.setMode */
+ public void halSetMode(long halPtr, int mode, boolean enabled) {
+ nativeSetMode(halPtr, mode, enabled);
+ }
+
}
@VisibleForTesting
@@ -552,7 +560,7 @@
if (mHalSessionPtr == 0 || !updateHintAllowed()) {
return;
}
- Preconditions.checkArgument(hint >= 0, "the hint ID the hint value should be"
+ Preconditions.checkArgument(hint >= 0, "the hint ID value should be"
+ " greater than zero.");
mNativeWrapper.halSendHint(mHalSessionPtr, hint);
}
@@ -593,6 +601,18 @@
return mThreadIds;
}
+ @Override
+ public void setMode(int mode, boolean enabled) {
+ synchronized (mLock) {
+ if (mHalSessionPtr == 0 || !updateHintAllowed()) {
+ return;
+ }
+ Preconditions.checkArgument(mode >= 0, "the mode Id value should be"
+ + " greater than zero.");
+ mNativeWrapper.halSetMode(mHalSessionPtr, mode, enabled);
+ }
+ }
+
private void onProcStateChanged() {
updateHintAllowed();
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 101af4d..405b133 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -94,7 +94,10 @@
cc_defaults {
name: "libservices.core-libs",
- defaults: ["android.hardware.graphics.common-ndk_shared"],
+ defaults: [
+ "android.hardware.graphics.common-ndk_shared",
+ "android.hardware.power-ndk_shared",
+ ],
shared_libs: [
"libadb_pairing_server",
"libadb_pairing_connection",
@@ -177,7 +180,6 @@
"android.hardware.power@1.1",
"android.hardware.power@1.2",
"android.hardware.power@1.3",
- "android.hardware.power-V4-ndk",
"android.hardware.power.stats@1.0",
"android.hardware.power.stats-V1-ndk",
"android.hardware.thermal@1.0",
diff --git a/services/core/jni/com_android_server_hint_HintManagerService.cpp b/services/core/jni/com_android_server_hint_HintManagerService.cpp
index e148b94..7edf445 100644
--- a/services/core/jni/com_android_server_hint_HintManagerService.cpp
+++ b/services/core/jni/com_android_server_hint_HintManagerService.cpp
@@ -31,6 +31,7 @@
using aidl::android::hardware::power::IPowerHintSession;
using aidl::android::hardware::power::SessionHint;
+using aidl::android::hardware::power::SessionMode;
using aidl::android::hardware::power::WorkDuration;
using android::base::StringPrintf;
@@ -41,6 +42,15 @@
static std::unordered_map<jlong, std::shared_ptr<IPowerHintSession>> gSessionMap;
static std::mutex gSessionMapLock;
+static int64_t getHintSessionPreferredRate() {
+ int64_t rate = -1;
+ auto result = gPowerHalController.getHintSessionPreferredRate();
+ if (result.isOk()) {
+ rate = result.value();
+ }
+ return rate;
+}
+
static jlong createHintSession(JNIEnv* env, int32_t tgid, int32_t uid,
std::vector<int32_t> threadIds, int64_t durationNanos) {
auto result = gPowerHalController.createHintSession(tgid, uid, threadIds, durationNanos);
@@ -93,13 +103,9 @@
appSession->setThreads(threadIds);
}
-static int64_t getHintSessionPreferredRate() {
- int64_t rate = -1;
- auto result = gPowerHalController.getHintSessionPreferredRate();
- if (result.isOk()) {
- rate = result.value();
- }
- return rate;
+static void setMode(int64_t session_ptr, SessionMode mode, bool enabled) {
+ auto appSession = reinterpret_cast<IPowerHintSession*>(session_ptr);
+ appSession->setMode(mode, enabled);
}
// ----------------------------------------------------------------------------
@@ -107,6 +113,10 @@
gPowerHalController.init();
}
+static jlong nativeGetHintSessionPreferredRate(JNIEnv* /* env */, jclass /* clazz */) {
+ return static_cast<jlong>(getHintSessionPreferredRate());
+}
+
static jlong nativeCreateHintSession(JNIEnv* env, jclass /* clazz */, jint tgid, jint uid,
jintArray tids, jlong durationNanos) {
ScopedIntArrayRO tidArray(env, tids);
@@ -165,14 +175,16 @@
setThreads(session_ptr, threadIds);
}
-static jlong nativeGetHintSessionPreferredRate(JNIEnv* /* env */, jclass /* clazz */) {
- return static_cast<jlong>(getHintSessionPreferredRate());
+static void nativeSetMode(JNIEnv* env, jclass /* clazz */, jlong session_ptr, jint mode,
+ jboolean enabled) {
+ setMode(session_ptr, static_cast<SessionMode>(mode), enabled);
}
// ----------------------------------------------------------------------------
static const JNINativeMethod sHintManagerServiceMethods[] = {
/* name, signature, funcPtr */
{"nativeInit", "()V", (void*)nativeInit},
+ {"nativeGetHintSessionPreferredRate", "()J", (void*)nativeGetHintSessionPreferredRate},
{"nativeCreateHintSession", "(II[IJ)J", (void*)nativeCreateHintSession},
{"nativePauseHintSession", "(J)V", (void*)nativePauseHintSession},
{"nativeResumeHintSession", "(J)V", (void*)nativeResumeHintSession},
@@ -181,7 +193,7 @@
{"nativeReportActualWorkDuration", "(J[J[J)V", (void*)nativeReportActualWorkDuration},
{"nativeSendHint", "(JI)V", (void*)nativeSendHint},
{"nativeSetThreads", "(J[I)V", (void*)nativeSetThreads},
- {"nativeGetHintSessionPreferredRate", "()J", (void*)nativeGetHintSessionPreferredRate},
+ {"nativeSetMode", "(JIZ)V", (void*)nativeSetMode},
};
int register_android_server_HintManagerService(JNIEnv* env) {
diff --git a/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java
index 726a4e2..9fca513 100644
--- a/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java
@@ -27,10 +27,11 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
@@ -73,6 +74,7 @@
private static final int TGID = Process.getThreadGroupLeader(TID);
private static final int[] SESSION_TIDS_A = new int[] {TID};
private static final int[] SESSION_TIDS_B = new int[] {TID};
+ private static final int[] SESSION_TIDS_C = new int[] {TID};
private static final long[] DURATIONS_THREE = new long[] {1L, 100L, 1000L};
private static final long[] TIMESTAMPS_THREE = new long[] {1L, 2L, 3L};
private static final long[] DURATIONS_ZERO = new long[] {};
@@ -94,6 +96,8 @@
eq(DEFAULT_TARGET_DURATION))).thenReturn(1L);
when(mNativeWrapperMock.halCreateHintSession(eq(TGID), eq(UID), eq(SESSION_TIDS_B),
eq(DEFAULT_TARGET_DURATION))).thenReturn(2L);
+ when(mNativeWrapperMock.halCreateHintSession(eq(TGID), eq(UID), eq(SESSION_TIDS_C),
+ eq(0L))).thenReturn(1L);
when(mAmInternalMock.getIsolatedProcesses(anyInt())).thenReturn(null);
LocalServices.removeServiceForTest(ActivityManagerInternal.class);
LocalServices.addService(ActivityManagerInternal.class, mAmInternalMock);
@@ -138,6 +142,10 @@
IHintSession b = service.getBinderServiceInstance().createHintSession(token,
SESSION_TIDS_B, DEFAULT_TARGET_DURATION);
assertNotEquals(a, b);
+
+ IHintSession c = service.getBinderServiceInstance().createHintSession(token,
+ SESSION_TIDS_C, 0L);
+ assertNotNull(c);
}
@Test
@@ -338,4 +346,35 @@
a.setThreads(SESSION_TIDS_A);
verify(mNativeWrapperMock, never()).halSetThreads(anyLong(), any());
}
+
+ @Test
+ public void testSetMode() throws Exception {
+ HintManagerService service = createService();
+ IBinder token = new Binder();
+
+ AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
+ .createHintSession(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
+
+ a.setMode(0, true);
+ verify(mNativeWrapperMock, times(1)).halSetMode(anyLong(),
+ eq(0), eq(true));
+
+ a.setMode(0, false);
+ verify(mNativeWrapperMock, times(1)).halSetMode(anyLong(),
+ eq(0), eq(false));
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ a.setMode(-1, true);
+ });
+
+ reset(mNativeWrapperMock);
+ // Set session to background, then the duration would not be updated.
+ service.mUidObserver.onUidStateChanged(
+ a.mUid, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
+ FgThread.getHandler().runWithScissors(() -> { }, 500);
+ assertFalse(a.updateHintAllowed());
+ a.setMode(0, true);
+ verify(mNativeWrapperMock, never()).halSetMode(anyLong(), anyInt(), anyBoolean());
+ }
+
}