Fix the setThreads JNI to throw SecurityException

Bug: 291830812
Test: atest FrameworksCoreTests:PerformanceHintManagerTest PerformanceHintTest
Change-Id: I35b28772c1ad2cf26e9f9f7f019406ef7c15303e
This commit is contained in:
Xiang Wang
2023-07-18 17:58:10 -07:00
parent d91397a63e
commit bee6f16d13
5 changed files with 47 additions and 7 deletions

View File

@@ -29,6 +29,7 @@ import java.io.Closeable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.Reference;
import java.util.Objects;
/** The PerformanceHintManager allows apps to send performance hint to system. */
@@ -239,6 +240,7 @@ public final class PerformanceHintManager {
if (mNativeSessionPtr == 0) {
return;
}
Objects.requireNonNull(tids, "tids cannot be null");
if (tids.length == 0) {
throw new IllegalArgumentException("Thread id list can't be empty.");
}

View File

@@ -41,7 +41,7 @@ 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 pid_t*, size_t);
typedef int (*APH_setThreads)(APerformanceHintSession*, const pid_t*, size_t);
typedef void (*APH_getThreadIds)(APerformanceHintSession*, int32_t* const, size_t* const);
bool gAPerformanceHintBindingInitialized = false;
@@ -112,6 +112,20 @@ void ensureAPerformanceHintBindingInitialized() {
} // namespace
static void throwExceptionForErrno(JNIEnv* env, int err, const std::string& msg) {
switch (err) {
case EINVAL:
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", msg.c_str());
break;
case EPERM:
jniThrowExceptionFmt(env, "java/lang/SecurityException", msg.c_str());
break;
default:
jniThrowException(env, "java/lang/RuntimeException", msg.c_str());
break;
}
}
static jlong nativeAcquireManager(JNIEnv* env, jclass clazz) {
ensureAPerformanceHintBindingInitialized();
return reinterpret_cast<jlong>(gAPH_getManagerFn());
@@ -174,8 +188,11 @@ static void nativeSetThreads(JNIEnv* env, jclass clazz, jlong nativeSessionPtr,
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());
int err = gAPH_setThreadsFn(reinterpret_cast<APerformanceHintSession*>(nativeSessionPtr),
tidsVector.data(), tidsVector.size());
if (err != 0) {
throwExceptionForErrno(env, err, "Failed to set threads for hint session");
}
}
// This call should only be used for validation in tests only. This call will initiate two IPC

View File

@@ -139,11 +139,20 @@ public class PerformanceHintManagerTest {
}
@Test
public void testSetThreadsWithIllegalArgument() {
public void testSetThreads_emptyTids() {
Session session = createSession();
assumeNotNull(session);
assertThrows(IllegalArgumentException.class, () -> {
session.setThreads(new int[] { });
session.setThreads(new int[]{});
});
}
@Test
public void testSetThreads_invalidTids() {
Session session = createSession();
assumeNotNull(session);
assertThrows(SecurityException.class, () -> {
session.setThreads(new int[]{-1});
});
}
}

View File

@@ -274,9 +274,10 @@ int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t 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) {
if (ret.exceptionCode() == binder::Status::Exception::EX_ILLEGAL_ARGUMENT) {
return EINVAL;
} else if (ret.exceptionCode() == binder::Status::Exception::EX_SECURITY) {
return EPERM;
}
return EPIPE;
}

View File

@@ -178,4 +178,15 @@ TEST_F(PerformanceHintTest, SetThreads) {
.WillOnce(Return(Status()));
result = APerformanceHint_setThreads(session, newTids.data(), newTids.size());
EXPECT_EQ(0, result);
testing::Mock::VerifyAndClearExpectations(mMockIHintManager);
std::vector<int32_t> invalidTids;
auto status = Status::fromExceptionCode(binder::Status::Exception::EX_SECURITY);
invalidTids.push_back(4);
invalidTids.push_back(6);
EXPECT_CALL(*mMockIHintManager, setHintSessionThreads(_, Eq(invalidTids)))
.Times(Exactly(1))
.WillOnce(Return(status));
result = APerformanceHint_setThreads(session, invalidTids.data(), invalidTids.size());
EXPECT_EQ(EPERM, result);
}