Add support for ADPF HintSession sendHint to JNI

* Add sendHint API to HintManagerService and PerformanceHintManager
 * Plumb relevant calls through the existing implementation
 * Extend existing tests to cover new API calls
 * Update the relevant build files to use power API v4

Bug: b/243973548
Test: atest PerformanceHintNativeTestCases
Test: atest FrameworksCoreTests:android.os.PerformanceHintManagerTest
Test: atest HintManagerServiceTest

Change-Id: Ice7ed8f32e877bd845afad77fcc6ae16f1a1b78c
This commit is contained in:
Matt Buckley
2022-09-28 20:54:46 +00:00
parent 4624189b1f
commit 354cc0a140
13 changed files with 183 additions and 3 deletions

View File

@@ -32165,7 +32165,12 @@ package android.os {
public static class PerformanceHintManager.Session implements java.io.Closeable {
method public void close();
method public void reportActualWorkDuration(long);
method public void sendHint(int);
method public void updateTargetWorkDuration(long);
field public static final int CPU_LOAD_DOWN = 1; // 0x1
field public static final int CPU_LOAD_RESET = 2; // 0x2
field public static final int CPU_LOAD_RESUME = 3; // 0x3
field public static final int CPU_LOAD_UP = 0; // 0x0
}
public final class PersistableBundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {

View File

@@ -22,4 +22,5 @@ oneway interface IHintSession {
void updateTargetWorkDuration(long targetDurationNanos);
void reportActualWorkDuration(in long[] actualDurationNanos, in long[] timeStampNanos);
void close();
void sendHint(int hint);
}

View File

@@ -16,6 +16,7 @@
package android.os;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemService;
@@ -24,6 +25,10 @@ import android.content.Context;
import com.android.internal.util.Preconditions;
import java.io.Closeable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.Reference;
/** The PerformanceHintManager allows apps to send performance hint to system. */
@SystemService(Context.PERFORMANCE_HINT_SERVICE)
@@ -104,6 +109,40 @@ public final class PerformanceHintManager {
mNativeSessionPtr = nativeSessionPtr;
}
/**
* This hint indicates a sudden increase in CPU workload intensity. It means
* that this hint session needs extra CPU resources immediately to meet the
* target duration for the current work cycle.
*/
public static final int CPU_LOAD_UP = 0;
/**
* This hint indicates a decrease in CPU workload intensity. It means that
* this hint session can reduce CPU resources and still meet the target duration.
*/
public static final int CPU_LOAD_DOWN = 1;
/*
* This hint indicates an upcoming CPU workload that is completely changed and
* unknown. It means that the hint session should reset CPU resources to a known
* baseline to prepare for an arbitrary load, and must wake up if inactive.
*/
public static final int CPU_LOAD_RESET = 2;
/*
* This hint indicates that the most recent CPU workload is resuming after a
* period of inactivity. It means that the hint session should allocate similar
* CPU resources to what was used previously, and must wake up if inactive.
*/
public static final int CPU_LOAD_RESUME = 3;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"CPU_LOAD_"}, value = {
CPU_LOAD_UP,
CPU_LOAD_DOWN,
CPU_LOAD_RESET,
CPU_LOAD_RESUME
})
public @interface Hint {}
/** @hide */
@Override
protected void finalize() throws Throwable {
@@ -152,6 +191,21 @@ public final class PerformanceHintManager {
mNativeSessionPtr = 0;
}
}
/**
* Sends performance hints to inform the hint session of changes in the workload.
*
* @param hint The hint to send to the session.
*/
public void sendHint(@Hint int hint) {
Preconditions.checkArgumentNonNegative(hint, "the hint ID should be at least"
+ " zero.");
try {
nativeSendHint(mNativeSessionPtr, hint);
} finally {
Reference.reachabilityFence(this);
}
}
}
private static native long nativeAcquireManager();
@@ -163,4 +217,5 @@ public final class PerformanceHintManager {
private static native void nativeReportActualWorkDuration(long nativeSessionPtr,
long actualDurationNanos);
private static native void nativeCloseSession(long nativeSessionPtr);
private static native void nativeSendHint(long nativeSessionPtr, int hint);
}

View File

@@ -40,6 +40,7 @@ typedef int64_t (*APH_getPreferredUpdateRateNanos)(APerformanceHintManager* mana
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);
bool gAPerformanceHintBindingInitialized = false;
APH_getManager gAPH_getManagerFn = nullptr;
@@ -48,6 +49,7 @@ APH_getPreferredUpdateRateNanos gAPH_getPreferredUpdateRateNanosFn = nullptr;
APH_updateTargetWorkDuration gAPH_updateTargetWorkDurationFn = nullptr;
APH_reportActualWorkDuration gAPH_reportActualWorkDurationFn = nullptr;
APH_closeSession gAPH_closeSessionFn = nullptr;
APH_sendHint gAPH_sendHintFn = nullptr;
void ensureAPerformanceHintBindingInitialized() {
if (gAPerformanceHintBindingInitialized) return;
@@ -88,6 +90,11 @@ void ensureAPerformanceHintBindingInitialized() {
LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr,
"Failed to find required symbol APerformanceHint_closeSession!");
gAPH_sendHintFn = (APH_sendHint)dlsym(handle_, "APerformanceHint_sendHint");
LOG_ALWAYS_FATAL_IF(gAPH_sendHintFn == nullptr,
"Failed to find required symbol "
"APerformanceHint_sendHint!");
gAPerformanceHintBindingInitialized = true;
}
@@ -138,6 +145,11 @@ static void nativeCloseSession(JNIEnv* env, jclass clazz, jlong nativeSessionPtr
gAPH_closeSessionFn(reinterpret_cast<APerformanceHintSession*>(nativeSessionPtr));
}
static void nativeSendHint(JNIEnv* env, jclass clazz, jlong nativeSessionPtr, jint hint) {
ensureAPerformanceHintBindingInitialized();
gAPH_sendHintFn(reinterpret_cast<APerformanceHintSession*>(nativeSessionPtr), hint);
}
static const JNINativeMethod gPerformanceHintMethods[] = {
{"nativeAcquireManager", "()J", (void*)nativeAcquireManager},
{"nativeGetPreferredUpdateRateNanos", "(J)J", (void*)nativeGetPreferredUpdateRateNanos},
@@ -145,6 +157,7 @@ static const JNINativeMethod gPerformanceHintMethods[] = {
{"nativeUpdateTargetWorkDuration", "(JJ)V", (void*)nativeUpdateTargetWorkDuration},
{"nativeReportActualWorkDuration", "(JJ)V", (void*)nativeReportActualWorkDuration},
{"nativeCloseSession", "(J)V", (void*)nativeCloseSession},
{"nativeSendHint", "(JI)V", (void*)nativeSendHint},
};
int register_android_os_PerformanceHintManager(JNIEnv* env) {

View File

@@ -113,6 +113,23 @@ public class PerformanceHintManagerTest {
});
}
@Test
public void testSendHint() {
Session s = createSession();
assumeNotNull(s);
s.sendHint(Session.CPU_LOAD_UP);
s.sendHint(Session.CPU_LOAD_RESET);
}
@Test
public void testSendHintWithNegativeHint() {
Session s = createSession();
assumeNotNull(s);
assertThrows(IllegalArgumentException.class, () -> {
s.sendHint(-1);
});
}
@Test
public void testCloseHintSession() {
Session s = createSession();

View File

@@ -330,6 +330,7 @@ LIBANDROID {
APerformanceHint_updateTargetWorkDuration; # introduced=Tiramisu
APerformanceHint_reportActualWorkDuration; # introduced=Tiramisu
APerformanceHint_closeSession; # introduced=Tiramisu
APerformanceHint_sendHint; # introduced=UpsideDownCake
local:
*;
};

View File

@@ -61,6 +61,7 @@ public:
int updateTargetWorkDuration(int64_t targetDurationNanos);
int reportActualWorkDuration(int64_t actualDurationNanos);
int sendHint(int32_t hint);
private:
friend struct APerformanceHintManager;
@@ -159,7 +160,7 @@ int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNano
}
binder::Status ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
if (!ret.isOk()) {
ALOGE("%s: HintSessionn updateTargetWorkDuration failed: %s", __FUNCTION__,
ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
ret.exceptionMessage().c_str());
return EPIPE;
}
@@ -205,6 +206,21 @@ int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNano
return 0;
}
int APerformanceHintSession::sendHint(int32_t hint) {
if (hint < 0) {
ALOGE("%s: session hint value must be greater than zero", __FUNCTION__);
return EINVAL;
}
binder::Status ret = mHintSession->sendHint(hint);
if (!ret.isOk()) {
ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.exceptionMessage().c_str());
return EPIPE;
}
return 0;
}
// ===================================== C API
APerformanceHintManager* APerformanceHint_getManager() {
return APerformanceHintManager::getInstance();
@@ -230,6 +246,10 @@ int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
return session->reportActualWorkDuration(actualDurationNanos);
}
int APerformanceHint_sendHint(APerformanceHintSession* session, int32_t hint) {
return session->sendHint(hint);
}
void APerformanceHint_closeSession(APerformanceHintSession* session) {
delete session;
}

View File

@@ -51,6 +51,7 @@ public:
(const ::std::vector<int64_t>& actualDurationNanos,
const ::std::vector<int64_t>& timeStampNanos),
(override));
MOCK_METHOD(Status, sendHint, (int32_t hints), (override));
MOCK_METHOD(Status, close, (), (override));
MOCK_METHOD(IBinder*, onAsBinder, (), (override));
};
@@ -121,6 +122,15 @@ TEST_F(PerformanceHintTest, TestSession) {
result = APerformanceHint_reportActualWorkDuration(session, -1L);
EXPECT_EQ(EINVAL, result);
// Send both valid and invalid session hints
int hintId = 2;
EXPECT_CALL(*iSession, sendHint(Eq(2))).Times(Exactly(1));
result = APerformanceHint_sendHint(session, hintId);
EXPECT_EQ(0, result);
result = APerformanceHint_sendHint(session, -1);
EXPECT_EQ(EINVAL, result);
EXPECT_CALL(*iSession, close()).Times(Exactly(1));
APerformanceHint_closeSession(session);
}

View File

@@ -168,7 +168,7 @@ java_library_static {
"android.hardware.rebootescrow-V1-java",
"android.hardware.soundtrigger-V2.3-java",
"android.hardware.power.stats-V1-java",
"android.hardware.power-V3-java",
"android.hardware.power-V4-java",
"android.hidl.manager-V1.2-java",
"capture_state_listener-aidl-java",
"icu4j_calendar_astronomer",

View File

@@ -24,6 +24,7 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.IHintManager;
import android.os.IHintSession;
import android.os.PerformanceHintManager;
import android.os.Process;
import android.os.RemoteException;
import android.util.ArrayMap;
@@ -147,6 +148,8 @@ public final class HintManagerService extends SystemService {
private static native void nativeReportActualWorkDuration(
long halPtr, long[] actualDurationNanos, long[] timeStampNanos);
private static native void nativeSendHint(long halPtr, int hint);
private static native long nativeGetHintSessionPreferredRate();
/** Wrapper for HintManager.nativeInit */
@@ -186,6 +189,11 @@ public final class HintManagerService extends SystemService {
timeStampNanos);
}
/** Wrapper for HintManager.sendHint */
public void halSendHint(long halPtr, int hint) {
nativeSendHint(halPtr, hint);
}
/** Wrapper for HintManager.nativeGetHintSessionPreferredRate */
public long halGetHintSessionPreferredRate() {
return nativeGetHintSessionPreferredRate();
@@ -475,6 +483,18 @@ public final class HintManagerService extends SystemService {
}
}
@Override
public void sendHint(@PerformanceHintManager.Session.Hint int hint) {
synchronized (mLock) {
if (mHalSessionPtr == 0 || !updateHintAllowed()) {
return;
}
Preconditions.checkArgument(hint >= 0, "the hint ID the hint value should be"
+ " greater than zero.");
mNativeWrapper.halSendHint(mHalSessionPtr, hint);
}
}
private void onProcStateChanged() {
updateHintAllowed();
}

View File

@@ -170,7 +170,7 @@ cc_defaults {
"android.hardware.power@1.1",
"android.hardware.power@1.2",
"android.hardware.power@1.3",
"android.hardware.power-V3-cpp",
"android.hardware.power-V4-cpp",
"android.hardware.power.stats@1.0",
"android.hardware.power.stats-V1-ndk",
"android.hardware.thermal@1.0",

View File

@@ -34,6 +34,7 @@
#include "jni.h"
using android::hardware::power::IPowerHintSession;
using android::hardware::power::SessionHint;
using android::hardware::power::WorkDuration;
using android::base::StringPrintf;
@@ -81,6 +82,11 @@ static void reportActualWorkDuration(int64_t session_ptr,
appSession->reportActualWorkDuration(actualDurations);
}
static void sendHint(int64_t session_ptr, SessionHint hint) {
sp<IPowerHintSession> appSession = reinterpret_cast<IPowerHintSession*>(session_ptr);
appSession->sendHint(hint);
}
static int64_t getHintSessionPreferredRate() {
int64_t rate = -1;
auto result = gPowerHalController.getHintSessionPreferredRate();
@@ -139,6 +145,10 @@ static void nativeReportActualWorkDuration(JNIEnv* env, jclass /* clazz */, jlon
reportActualWorkDuration(session_ptr, actualList);
}
static void nativeSendHint(JNIEnv* env, jclass /* clazz */, jlong session_ptr, jint hint) {
sendHint(session_ptr, static_cast<SessionHint>(hint));
}
static jlong nativeGetHintSessionPreferredRate(JNIEnv* /* env */, jclass /* clazz */) {
return static_cast<jlong>(getHintSessionPreferredRate());
}
@@ -153,6 +163,7 @@ static const JNINativeMethod sHintManagerServiceMethods[] = {
{"nativeCloseHintSession", "(J)V", (void*)nativeCloseHintSession},
{"nativeUpdateTargetWorkDuration", "(JJ)V", (void*)nativeUpdateTargetWorkDuration},
{"nativeReportActualWorkDuration", "(J[J[J)V", (void*)nativeReportActualWorkDuration},
{"nativeSendHint", "(JI)V", (void*)nativeSendHint},
{"nativeGetHintSessionPreferredRate", "()J", (void*)nativeGetHintSessionPreferredRate},
};

View File

@@ -42,6 +42,7 @@ import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
import android.os.IHintSession;
import android.os.PerformanceHintManager;
import android.os.Process;
import com.android.server.FgThread;
@@ -249,6 +250,32 @@ public class HintManagerServiceTest {
verify(mNativeWrapperMock, never()).halReportActualWorkDuration(anyLong(), any(), any());
}
@Test
public void testSendHint() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
.createHintSession(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
a.sendHint(PerformanceHintManager.Session.CPU_LOAD_RESET);
verify(mNativeWrapperMock, times(1)).halSendHint(anyLong(),
eq(PerformanceHintManager.Session.CPU_LOAD_RESET));
assertThrows(IllegalArgumentException.class, () -> {
a.sendHint(-1);
});
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.sendHint(PerformanceHintManager.Session.CPU_LOAD_RESET);
verify(mNativeWrapperMock, never()).halSendHint(anyLong(), anyInt());
}
@Test
public void testDoHintInBackground() throws Exception {
HintManagerService service = createService();