Merge "Implement setThreads APIs for PerformanceHintManager.Session."
This commit is contained in:
@@ -32519,6 +32519,7 @@ package android.os {
|
||||
public static class PerformanceHintManager.Session implements java.io.Closeable {
|
||||
method public void close();
|
||||
method public void reportActualWorkDuration(long);
|
||||
method public void setThreads(@NonNull int[]);
|
||||
method public void updateTargetWorkDuration(long);
|
||||
}
|
||||
|
||||
|
||||
@@ -1861,6 +1861,7 @@ package android.os {
|
||||
}
|
||||
|
||||
public static class PerformanceHintManager.Session implements java.io.Closeable {
|
||||
method @Nullable public int[] getThreadIds();
|
||||
method public void sendHint(int);
|
||||
field public static final int CPU_LOAD_DOWN = 1; // 0x1
|
||||
field public static final int CPU_LOAD_RESET = 2; // 0x2
|
||||
|
||||
@@ -24,10 +24,13 @@ interface IHintManager {
|
||||
/**
|
||||
* Creates a {@link Session} for the given set of threads and associates to a binder token.
|
||||
*/
|
||||
IHintSession createHintSession(in IBinder token, in int[] tids, long durationNanos);
|
||||
IHintSession createHintSession(in IBinder token, in int[] tids, long durationNanos);
|
||||
|
||||
/**
|
||||
* Get preferred rate limit in nano second.
|
||||
*/
|
||||
long getHintSessionPreferredRate();
|
||||
long getHintSessionPreferredRate();
|
||||
|
||||
void setHintSessionThreads(in IHintSession hintSession, in int[] tids);
|
||||
int[] getHintSessionThreadIds(in IHintSession hintSession);
|
||||
}
|
||||
|
||||
@@ -222,16 +222,50 @@ public final class PerformanceHintManager {
|
||||
Reference.reachabilityFence(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param tids The list of threads to be associated with this session. They must be
|
||||
* part of this app's thread group.
|
||||
*
|
||||
* @throws IllegalStateException if the hint session is not in the foreground.
|
||||
* @throws IllegalArgumentException if the thread id list is empty.
|
||||
* @throws SecurityException if any thread id doesn't belong to the application.
|
||||
*/
|
||||
public void setThreads(@NonNull int[] tids) {
|
||||
if (mNativeSessionPtr == 0) {
|
||||
return;
|
||||
}
|
||||
if (tids.length == 0) {
|
||||
throw new IllegalArgumentException("Thread id list can't be empty.");
|
||||
}
|
||||
nativeSetThreads(mNativeSessionPtr, tids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of thread ids.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
public @Nullable int[] getThreadIds() {
|
||||
return nativeGetThreadIds(mNativeSessionPtr);
|
||||
}
|
||||
}
|
||||
|
||||
private static native long nativeAcquireManager();
|
||||
private static native long nativeGetPreferredUpdateRateNanos(long nativeManagerPtr);
|
||||
private static native long nativeCreateSession(long nativeManagerPtr,
|
||||
int[] tids, long initialTargetWorkDurationNanos);
|
||||
private static native int[] nativeGetThreadIds(long nativeSessionPtr);
|
||||
private static native void nativeUpdateTargetWorkDuration(long nativeSessionPtr,
|
||||
long targetDurationNanos);
|
||||
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);
|
||||
private static native void nativeSetThreads(long nativeSessionPtr, int[] tids);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ 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 void (*APH_setThreads)(APerformanceHintSession*, const int32_t*, size_t);
|
||||
typedef void (*APH_getThreadIds)(APerformanceHintSession*, int32_t* const, size_t* const);
|
||||
|
||||
bool gAPerformanceHintBindingInitialized = false;
|
||||
APH_getManager gAPH_getManagerFn = nullptr;
|
||||
@@ -50,6 +52,8 @@ 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;
|
||||
|
||||
void ensureAPerformanceHintBindingInitialized() {
|
||||
if (gAPerformanceHintBindingInitialized) return;
|
||||
@@ -95,6 +99,14 @@ void ensureAPerformanceHintBindingInitialized() {
|
||||
"Failed to find required symbol "
|
||||
"APerformanceHint_sendHint!");
|
||||
|
||||
gAPH_setThreadsFn = (APH_setThreads)dlsym(handle_, "APerformanceHint_setThreads");
|
||||
LOG_ALWAYS_FATAL_IF(gAPH_setThreadsFn == nullptr,
|
||||
"Failed to find required symbol APerformanceHint_setThreads!");
|
||||
|
||||
gAPH_getThreadIdsFn = (APH_getThreadIds)dlsym(handle_, "APerformanceHint_getThreadIds");
|
||||
LOG_ALWAYS_FATAL_IF(gAPH_getThreadIdsFn == nullptr,
|
||||
"Failed to find required symbol APerformanceHint_getThreadIds!");
|
||||
|
||||
gAPerformanceHintBindingInitialized = true;
|
||||
}
|
||||
|
||||
@@ -150,6 +162,50 @@ static void nativeSendHint(JNIEnv* env, jclass clazz, jlong nativeSessionPtr, ji
|
||||
gAPH_sendHintFn(reinterpret_cast<APerformanceHintSession*>(nativeSessionPtr), hint);
|
||||
}
|
||||
|
||||
static void nativeSetThreads(JNIEnv* env, jclass clazz, jlong nativeSessionPtr, jintArray tids) {
|
||||
ensureAPerformanceHintBindingInitialized();
|
||||
|
||||
if (tids == nullptr) {
|
||||
return;
|
||||
}
|
||||
ScopedIntArrayRO tidsArray(env, tids);
|
||||
std::vector<int32_t> tidsVector;
|
||||
tidsVector.reserve(tidsArray.size());
|
||||
for (size_t i = 0; i < tidsArray.size(); ++i) {
|
||||
tidsVector.push_back(static_cast<int32_t>(tidsArray[i]));
|
||||
}
|
||||
gAPH_setThreadsFn(reinterpret_cast<APerformanceHintSession*>(nativeSessionPtr),
|
||||
tidsVector.data(), tidsVector.size());
|
||||
}
|
||||
|
||||
// This call should only be used for validation in tests only. This call will initiate two IPC
|
||||
// calls, the first one is used to determined the size of the thread ids list, the second one
|
||||
// is used to return the actual list.
|
||||
static jintArray nativeGetThreadIds(JNIEnv* env, jclass clazz, jlong nativeSessionPtr) {
|
||||
ensureAPerformanceHintBindingInitialized();
|
||||
size_t size = 0;
|
||||
gAPH_getThreadIdsFn(reinterpret_cast<APerformanceHintSession*>(nativeSessionPtr), nullptr,
|
||||
&size);
|
||||
if (size == 0) {
|
||||
jintArray jintArr = env->NewIntArray(0);
|
||||
return jintArr;
|
||||
}
|
||||
std::vector<int32_t> tidsVector(size);
|
||||
gAPH_getThreadIdsFn(reinterpret_cast<APerformanceHintSession*>(nativeSessionPtr),
|
||||
tidsVector.data(), &size);
|
||||
jintArray jintArr = env->NewIntArray(size);
|
||||
if (jintArr == nullptr) {
|
||||
jniThrowException(env, "java/lang/OutOfMemoryError", nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
jint* threadIds = env->GetIntArrayElements(jintArr, 0);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
threadIds[i] = tidsVector[i];
|
||||
}
|
||||
env->ReleaseIntArrayElements(jintArr, threadIds, 0);
|
||||
return jintArr;
|
||||
}
|
||||
|
||||
static const JNINativeMethod gPerformanceHintMethods[] = {
|
||||
{"nativeAcquireManager", "()J", (void*)nativeAcquireManager},
|
||||
{"nativeGetPreferredUpdateRateNanos", "(J)J", (void*)nativeGetPreferredUpdateRateNanos},
|
||||
@@ -158,6 +214,8 @@ static const JNINativeMethod gPerformanceHintMethods[] = {
|
||||
{"nativeReportActualWorkDuration", "(JJ)V", (void*)nativeReportActualWorkDuration},
|
||||
{"nativeCloseSession", "(J)V", (void*)nativeCloseSession},
|
||||
{"nativeSendHint", "(JI)V", (void*)nativeSendHint},
|
||||
{"nativeSetThreads", "(J[I)V", (void*)nativeSetThreads},
|
||||
{"nativeGetThreadIds", "(J)[I", (void*)nativeGetThreadIds},
|
||||
};
|
||||
|
||||
int register_android_os_PerformanceHintManager(JNIEnv* env) {
|
||||
|
||||
@@ -137,4 +137,13 @@ public class PerformanceHintManagerTest {
|
||||
assumeNotNull(s);
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetThreadsWithIllegalArgument() {
|
||||
Session session = createSession();
|
||||
assumeNotNull(session);
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
session.setThreads(new int[] { });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,6 +330,7 @@ LIBANDROID {
|
||||
APerformanceHint_updateTargetWorkDuration; # introduced=Tiramisu
|
||||
APerformanceHint_reportActualWorkDuration; # introduced=Tiramisu
|
||||
APerformanceHint_closeSession; # introduced=Tiramisu
|
||||
APerformanceHint_setThreads; # introduced=UpsideDownCake
|
||||
local:
|
||||
*;
|
||||
};
|
||||
@@ -338,6 +339,7 @@ LIBANDROID_PLATFORM {
|
||||
global:
|
||||
APerformanceHint_setIHintManagerForTesting;
|
||||
APerformanceHint_sendHint;
|
||||
APerformanceHint_getThreadIds;
|
||||
extern "C++" {
|
||||
ASurfaceControl_registerSurfaceStatsListener*;
|
||||
ASurfaceControl_unregisterSurfaceStatsListener*;
|
||||
|
||||
@@ -62,18 +62,21 @@ private:
|
||||
|
||||
struct APerformanceHintSession {
|
||||
public:
|
||||
APerformanceHintSession(sp<IHintSession> session, int64_t preferredRateNanos,
|
||||
int64_t targetDurationNanos);
|
||||
APerformanceHintSession(sp<IHintManager> hintManager, sp<IHintSession> session,
|
||||
int64_t preferredRateNanos, int64_t targetDurationNanos);
|
||||
APerformanceHintSession() = delete;
|
||||
~APerformanceHintSession();
|
||||
|
||||
int updateTargetWorkDuration(int64_t targetDurationNanos);
|
||||
int reportActualWorkDuration(int64_t actualDurationNanos);
|
||||
int sendHint(int32_t hint);
|
||||
int setThreads(const int32_t* threadIds, size_t size);
|
||||
int getThreadIds(int32_t* const threadIds, size_t* size);
|
||||
|
||||
private:
|
||||
friend struct APerformanceHintManager;
|
||||
|
||||
sp<IHintManager> mHintManager;
|
||||
sp<IHintSession> mHintSession;
|
||||
// HAL preferred update rate
|
||||
const int64_t mPreferredRateNanos;
|
||||
@@ -140,7 +143,7 @@ APerformanceHintSession* APerformanceHintManager::createSession(
|
||||
if (!ret.isOk() || !session) {
|
||||
return nullptr;
|
||||
}
|
||||
return new APerformanceHintSession(std::move(session), mPreferredRateNanos,
|
||||
return new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
|
||||
initialTargetWorkDurationNanos);
|
||||
}
|
||||
|
||||
@@ -150,10 +153,12 @@ int64_t APerformanceHintManager::getPreferredRateNanos() const {
|
||||
|
||||
// ===================================== APerformanceHintSession implementation
|
||||
|
||||
APerformanceHintSession::APerformanceHintSession(sp<IHintSession> session,
|
||||
APerformanceHintSession::APerformanceHintSession(sp<IHintManager> hintManager,
|
||||
sp<IHintSession> session,
|
||||
int64_t preferredRateNanos,
|
||||
int64_t targetDurationNanos)
|
||||
: mHintSession(std::move(session)),
|
||||
: mHintManager(hintManager),
|
||||
mHintSession(std::move(session)),
|
||||
mPreferredRateNanos(preferredRateNanos),
|
||||
mTargetDurationNanos(targetDurationNanos),
|
||||
mFirstTargetMetTimestamp(0),
|
||||
@@ -260,6 +265,47 @@ int APerformanceHintSession::sendHint(int32_t hint) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
|
||||
if (size == 0) {
|
||||
ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__);
|
||||
return EINVAL;
|
||||
}
|
||||
std::vector<int32_t> tids(threadIds, threadIds + size);
|
||||
binder::Status ret = mHintManager->setHintSessionThreads(mHintSession, tids);
|
||||
if (!ret.isOk()) {
|
||||
ALOGE("%s: failed: %s", __FUNCTION__, ret.exceptionMessage().c_str());
|
||||
if (ret.exceptionCode() == binder::Status::Exception::EX_SECURITY ||
|
||||
ret.exceptionCode() == binder::Status::Exception::EX_ILLEGAL_ARGUMENT) {
|
||||
return EINVAL;
|
||||
}
|
||||
return EPIPE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size) {
|
||||
std::vector<int32_t> tids;
|
||||
binder::Status ret = mHintManager->getHintSessionThreadIds(mHintSession, &tids);
|
||||
if (!ret.isOk()) {
|
||||
ALOGE("%s: failed: %s", __FUNCTION__, ret.exceptionMessage().c_str());
|
||||
return EPIPE;
|
||||
}
|
||||
|
||||
// When threadIds is nullptr, this is the first call to determine the size
|
||||
// of the thread ids list.
|
||||
if (threadIds == nullptr) {
|
||||
*size = tids.size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Second call to return the actual list of thread ids.
|
||||
*size = tids.size();
|
||||
for (size_t i = 0; i < *size; ++i) {
|
||||
threadIds[i] = tids[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ===================================== C API
|
||||
APerformanceHintManager* APerformanceHint_getManager() {
|
||||
return APerformanceHintManager::getInstance();
|
||||
@@ -293,6 +339,23 @@ int APerformanceHint_sendHint(void* session, int32_t hint) {
|
||||
return reinterpret_cast<APerformanceHintSession*>(session)->sendHint(hint);
|
||||
}
|
||||
|
||||
int APerformanceHint_setThreads(APerformanceHintSession* session, const int32_t* threadIds,
|
||||
size_t size) {
|
||||
if (session == nullptr) {
|
||||
return EINVAL;
|
||||
}
|
||||
return session->setThreads(threadIds, size);
|
||||
}
|
||||
|
||||
int APerformanceHint_getThreadIds(void* aPerformanceHintSession, int32_t* const threadIds,
|
||||
size_t* const size) {
|
||||
if (aPerformanceHintSession == nullptr) {
|
||||
return EINVAL;
|
||||
}
|
||||
return static_cast<APerformanceHintSession*>(aPerformanceHintSession)
|
||||
->getThreadIds(threadIds, size);
|
||||
}
|
||||
|
||||
void APerformanceHint_setIHintManagerForTesting(void* iManager) {
|
||||
delete gHintManagerForTesting;
|
||||
gHintManagerForTesting = nullptr;
|
||||
|
||||
@@ -37,10 +37,15 @@ using namespace testing;
|
||||
class MockIHintManager : public IHintManager {
|
||||
public:
|
||||
MOCK_METHOD(Status, createHintSession,
|
||||
(const ::android::sp<::android::IBinder>& token, const ::std::vector<int32_t>& tids,
|
||||
int64_t durationNanos, ::android::sp<::android::os::IHintSession>* _aidl_return),
|
||||
(const sp<IBinder>& token, const ::std::vector<int32_t>& tids,
|
||||
int64_t durationNanos, ::android::sp<IHintSession>* _aidl_return),
|
||||
(override));
|
||||
MOCK_METHOD(Status, getHintSessionPreferredRate, (int64_t * _aidl_return), (override));
|
||||
MOCK_METHOD(Status, setHintSessionThreads,
|
||||
(const sp<IHintSession>& hintSession, const ::std::vector<int32_t>& tids),
|
||||
(override));
|
||||
MOCK_METHOD(Status, getHintSessionThreadIds,
|
||||
(const sp<IHintSession>& hintSession, ::std::vector<int32_t>* tids), (override));
|
||||
MOCK_METHOD(IBinder*, onAsBinder, (), (override));
|
||||
};
|
||||
|
||||
@@ -141,3 +146,36 @@ TEST_F(PerformanceHintTest, TestSession) {
|
||||
EXPECT_CALL(*iSession, close()).Times(Exactly(1));
|
||||
APerformanceHint_closeSession(session);
|
||||
}
|
||||
|
||||
TEST_F(PerformanceHintTest, SetThreads) {
|
||||
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);
|
||||
|
||||
std::vector<int32_t> emptyTids;
|
||||
int result = APerformanceHint_setThreads(session, emptyTids.data(), emptyTids.size());
|
||||
EXPECT_EQ(EINVAL, result);
|
||||
|
||||
std::vector<int32_t> newTids;
|
||||
newTids.push_back(1);
|
||||
newTids.push_back(3);
|
||||
EXPECT_CALL(*mMockIHintManager, setHintSessionThreads(_, Eq(newTids)))
|
||||
.Times(Exactly(1))
|
||||
.WillOnce(Return(Status()));
|
||||
result = APerformanceHint_setThreads(session, newTids.data(), newTids.size());
|
||||
EXPECT_EQ(0, result);
|
||||
}
|
||||
|
||||
@@ -189,6 +189,8 @@ public final class HintManagerService extends SystemService {
|
||||
|
||||
private static native void nativeSendHint(long halPtr, int hint);
|
||||
|
||||
private static native void nativeSetThreads(long halPtr, int[] tids);
|
||||
|
||||
private static native long nativeGetHintSessionPreferredRate();
|
||||
|
||||
/** Wrapper for HintManager.nativeInit */
|
||||
@@ -237,6 +239,11 @@ public final class HintManagerService extends SystemService {
|
||||
public long halGetHintSessionPreferredRate() {
|
||||
return nativeGetHintSessionPreferredRate();
|
||||
}
|
||||
|
||||
/** Wrapper for HintManager.nativeSetThreads */
|
||||
public void halSetThreads(long halPtr, int[] tids) {
|
||||
nativeSetThreads(halPtr, tids);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -399,6 +406,18 @@ public final class HintManagerService extends SystemService {
|
||||
return mHintSessionPreferredRate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHintSessionThreads(@NonNull IHintSession hintSession, @NonNull int[] tids) {
|
||||
AppHintSession appHintSession = (AppHintSession) hintSession;
|
||||
appHintSession.setThreads(tids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getHintSessionThreadIds(@NonNull IHintSession hintSession) {
|
||||
AppHintSession appHintSession = (AppHintSession) hintSession;
|
||||
return appHintSession.getThreadIds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
|
||||
@@ -434,11 +453,12 @@ public final class HintManagerService extends SystemService {
|
||||
final class AppHintSession extends IHintSession.Stub implements IBinder.DeathRecipient {
|
||||
protected final int mUid;
|
||||
protected final int mPid;
|
||||
protected final int[] mThreadIds;
|
||||
protected int[] mThreadIds;
|
||||
protected final IBinder mToken;
|
||||
protected long mHalSessionPtr;
|
||||
protected long mTargetDurationNanos;
|
||||
protected boolean mUpdateAllowed;
|
||||
protected int[] mNewThreadIds;
|
||||
|
||||
protected AppHintSession(
|
||||
int uid, int pid, int[] threadIds, IBinder token,
|
||||
@@ -541,6 +561,38 @@ public final class HintManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
public void setThreads(@NonNull int[] tids) {
|
||||
synchronized (mLock) {
|
||||
if (mHalSessionPtr == 0) {
|
||||
return;
|
||||
}
|
||||
if (tids.length == 0) {
|
||||
throw new IllegalArgumentException("Thread id list can't be empty.");
|
||||
}
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int callingTgid = Process.getThreadGroupLeader(Binder.getCallingPid());
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
if (!checkTidValid(callingUid, callingTgid, tids)) {
|
||||
throw new SecurityException("Some tid doesn't belong to the application.");
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
if (!updateHintAllowed()) {
|
||||
Slogf.v(TAG, "update hint not allowed, storing tids.");
|
||||
mNewThreadIds = tids;
|
||||
return;
|
||||
}
|
||||
mNativeWrapper.halSetThreads(mHalSessionPtr, tids);
|
||||
mThreadIds = tids;
|
||||
}
|
||||
}
|
||||
|
||||
public int[] getThreadIds() {
|
||||
return mThreadIds;
|
||||
}
|
||||
|
||||
private void onProcStateChanged() {
|
||||
updateHintAllowed();
|
||||
}
|
||||
@@ -556,6 +608,11 @@ public final class HintManagerService extends SystemService {
|
||||
synchronized (mLock) {
|
||||
if (mHalSessionPtr == 0) return;
|
||||
mNativeWrapper.halResumeHintSession(mHalSessionPtr);
|
||||
if (mNewThreadIds != null) {
|
||||
mNativeWrapper.halSetThreads(mHalSessionPtr, mNewThreadIds);
|
||||
mThreadIds = mNewThreadIds;
|
||||
mNewThreadIds = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +87,11 @@ static void sendHint(int64_t session_ptr, SessionHint hint) {
|
||||
appSession->sendHint(hint);
|
||||
}
|
||||
|
||||
static void setThreads(int64_t session_ptr, const std::vector<int32_t>& threadIds) {
|
||||
sp<IPowerHintSession> appSession = reinterpret_cast<IPowerHintSession*>(session_ptr);
|
||||
appSession->setThreads(threadIds);
|
||||
}
|
||||
|
||||
static int64_t getHintSessionPreferredRate() {
|
||||
int64_t rate = -1;
|
||||
auto result = gPowerHalController.getHintSessionPreferredRate();
|
||||
@@ -149,6 +154,16 @@ static void nativeSendHint(JNIEnv* env, jclass /* clazz */, jlong session_ptr, j
|
||||
sendHint(session_ptr, static_cast<SessionHint>(hint));
|
||||
}
|
||||
|
||||
static void nativeSetThreads(JNIEnv* env, jclass /* clazz */, jlong session_ptr, jintArray tids) {
|
||||
ScopedIntArrayRO arrayThreadIds(env, tids);
|
||||
|
||||
std::vector<int32_t> threadIds(arrayThreadIds.size());
|
||||
for (size_t i = 0; i < arrayThreadIds.size(); i++) {
|
||||
threadIds[i] = arrayThreadIds[i];
|
||||
}
|
||||
setThreads(session_ptr, threadIds);
|
||||
}
|
||||
|
||||
static jlong nativeGetHintSessionPreferredRate(JNIEnv* /* env */, jclass /* clazz */) {
|
||||
return static_cast<jlong>(getHintSessionPreferredRate());
|
||||
}
|
||||
@@ -164,6 +179,7 @@ static const JNINativeMethod sHintManagerServiceMethods[] = {
|
||||
{"nativeUpdateTargetWorkDuration", "(JJ)V", (void*)nativeUpdateTargetWorkDuration},
|
||||
{"nativeReportActualWorkDuration", "(J[J[J)V", (void*)nativeReportActualWorkDuration},
|
||||
{"nativeSendHint", "(JI)V", (void*)nativeSendHint},
|
||||
{"nativeSetThreads", "(J[I)V", (void*)nativeSetThreads},
|
||||
{"nativeGetHintSessionPreferredRate", "()J", (void*)nativeGetHintSessionPreferredRate},
|
||||
};
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.server.power.hint;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
@@ -310,4 +311,32 @@ public class HintManagerServiceTest {
|
||||
a.mUid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0, 0);
|
||||
assertTrue(a.updateHintAllowed());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetThreads() throws Exception {
|
||||
HintManagerService service = createService();
|
||||
IBinder token = new Binder();
|
||||
|
||||
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
|
||||
.createHintSession(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
|
||||
|
||||
a.updateTargetWorkDuration(100L);
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
a.setThreads(new int[]{});
|
||||
});
|
||||
|
||||
a.setThreads(SESSION_TIDS_B);
|
||||
verify(mNativeWrapperMock, times(1)).halSetThreads(anyLong(), eq(SESSION_TIDS_B));
|
||||
assertArrayEquals(SESSION_TIDS_B, a.getThreadIds());
|
||||
|
||||
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.setThreads(SESSION_TIDS_A);
|
||||
verify(mNativeWrapperMock, never()).halSetThreads(anyLong(), any());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user