summaryrefslogtreecommitdiff
path: root/native
diff options
context:
space:
mode:
Diffstat (limited to 'native')
-rw-r--r--native/android/Android.bp6
-rw-r--r--native/android/TEST_MAPPING19
-rw-r--r--native/android/configuration.cpp2
-rw-r--r--native/android/libandroid.map.txt10
-rw-r--r--native/android/performance_hint.cpp191
-rw-r--r--native/android/system_fonts.cpp9
-rw-r--r--native/android/tests/performance_hint/PerformanceHintNativeTest.cpp187
-rw-r--r--native/android/tests/thermal/Android.bp65
-rw-r--r--native/android/tests/thermal/NativeThermalUnitTest.cpp158
-rw-r--r--native/android/tests/thermal/OWNERS1
-rw-r--r--native/android/thermal.cpp124
-rw-r--r--native/webview/TEST_MAPPING2
12 files changed, 689 insertions, 85 deletions
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 254eb4494ed8..7f3792d06795 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -46,7 +46,10 @@ cc_defaults {
cc_library_shared {
name: "libandroid",
- defaults: ["libandroid_defaults"],
+ defaults: [
+ "libandroid_defaults",
+ "android.hardware.power-ndk_shared",
+ ],
srcs: [
"activity_manager.cpp",
@@ -95,7 +98,6 @@ cc_library_shared {
"libpowermanager",
"android.hardware.configstore@1.0",
"android.hardware.configstore-utils",
- "android.hardware.power-V4-ndk",
"libnativedisplay",
],
diff --git a/native/android/TEST_MAPPING b/native/android/TEST_MAPPING
index 6a5d2c008b1d..7c710982e4f6 100644
--- a/native/android/TEST_MAPPING
+++ b/native/android/TEST_MAPPING
@@ -12,6 +12,25 @@
}
],
"file_patterns": ["permission_manager.cpp"]
+ },
+ {
+ "name": "CtsOsTestCases",
+ "options": [
+ {
+ "include-filter": "android.os.cts.PerformanceHintManagerTest"
+ }
+ ],
+ "file_patterns": ["performance_hint.cpp"]
+ }
+ ],
+ "postsubmit": [
+ {
+ "name": "CtsThermalTestCases",
+ "file_patterns": ["thermal.cpp"]
+ },
+ {
+ "name": "NativeThermalUnitTestCases",
+ "file_patterns": ["thermal.cpp"]
}
]
}
diff --git a/native/android/configuration.cpp b/native/android/configuration.cpp
index b50514d27bac..283445fc8a9a 100644
--- a/native/android/configuration.cpp
+++ b/native/android/configuration.cpp
@@ -36,7 +36,7 @@ void AConfiguration_delete(AConfiguration* config) {
void AConfiguration_fromAssetManager(AConfiguration* out, AAssetManager* am) {
ScopedLock<AssetManager2> locked_mgr(*AssetManagerForNdkAssetManager(am));
- ResTable_config config = locked_mgr->GetConfiguration();
+ ResTable_config config = locked_mgr->GetConfigurations()[0];
// AConfiguration is not a virtual subclass, so we can memcpy.
memcpy(out, &config, sizeof(config));
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 985305f02a82..960510879a4c 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -327,6 +327,7 @@ LIBANDROID {
AThermal_registerThermalStatusListener; # introduced=30
AThermal_unregisterThermalStatusListener; # introduced=30
AThermal_getThermalHeadroom; # introduced=31
+ AThermal_getThermalHeadroomThresholds; # introduced=VanillaIceCream
APerformanceHint_getManager; # introduced=Tiramisu
APerformanceHint_createSession; # introduced=Tiramisu
APerformanceHint_getPreferredUpdateRateNanos; # introduced=Tiramisu
@@ -334,12 +335,21 @@ LIBANDROID {
APerformanceHint_reportActualWorkDuration; # introduced=Tiramisu
APerformanceHint_closeSession; # introduced=Tiramisu
APerformanceHint_setThreads; # introduced=UpsideDownCake
+ APerformanceHint_setPreferPowerEfficiency; # introduced=VanillaIceCream
+ APerformanceHint_reportActualWorkDuration2; # introduced=VanillaIceCream
+ AWorkDuration_create; # introduced=VanillaIceCream
+ AWorkDuration_release; # introduced=VanillaIceCream
+ AWorkDuration_setWorkPeriodStartTimestampNanos; # introduced=VanillaIceCream
+ AWorkDuration_setActualTotalDurationNanos; # introduced=VanillaIceCream
+ AWorkDuration_setActualCpuDurationNanos; # introduced=VanillaIceCream
+ AWorkDuration_setActualGpuDurationNanos; # introduced=VanillaIceCream
local:
*;
};
LIBANDROID_PLATFORM {
global:
+ AThermal_setIThermalServiceForTesting;
APerformanceHint_setIHintManagerForTesting;
APerformanceHint_sendHint;
APerformanceHint_getThreadIds;
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index b3628fa3e5ce..c4c81284780e 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -17,12 +17,15 @@
#define LOG_TAG "perf_hint"
#include <aidl/android/hardware/power/SessionHint.h>
+#include <aidl/android/hardware/power/SessionMode.h>
+#include <android/WorkDuration.h>
#include <android/os/IHintManager.h>
#include <android/os/IHintSession.h>
#include <android/performance_hint.h>
#include <binder/Binder.h>
#include <binder/IBinder.h>
#include <binder/IServiceManager.h>
+#include <inttypes.h>
#include <performance_hint_private.h>
#include <utils/SystemClock.h>
@@ -36,6 +39,7 @@ using namespace android::os;
using namespace std::chrono_literals;
using AidlSessionHint = aidl::android::hardware::power::SessionHint;
+using AidlSessionMode = aidl::android::hardware::power::SessionMode;
struct APerformanceHintSession;
@@ -72,10 +76,14 @@ public:
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);
+ int reportActualWorkDuration(AWorkDuration* workDuration);
private:
friend struct APerformanceHintManager;
+ int reportActualWorkDurationInternal(WorkDuration* workDuration);
+
sp<IHintManager> mHintManager;
sp<IHintSession> mHintSession;
// HAL preferred update rate
@@ -89,8 +97,7 @@ private:
// Last hint reported from sendHint indexed by hint value
std::vector<int64_t> mLastHintSentTimestamp;
// Cached samples
- std::vector<int64_t> mActualDurationsNanos;
- std::vector<int64_t> mTimestampsNanos;
+ std::vector<WorkDuration> mActualWorkDurations;
};
static IHintManager* gIHintManagerForTesting = nullptr;
@@ -192,8 +199,7 @@ int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNano
* Most of the workload is target_duration dependent, so now clear the cached samples
* as they are most likely obsolete.
*/
- mActualDurationsNanos.clear();
- mTimestampsNanos.clear();
+ mActualWorkDurations.clear();
mFirstTargetMetTimestamp = 0;
mLastTargetMetTimestamp = 0;
return 0;
@@ -204,43 +210,10 @@ int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNano
ALOGE("%s: actualDurationNanos must be positive", __FUNCTION__);
return EINVAL;
}
- int64_t now = elapsedRealtimeNano();
- mActualDurationsNanos.push_back(actualDurationNanos);
- mTimestampsNanos.push_back(now);
-
- if (actualDurationNanos >= mTargetDurationNanos) {
- // Reset timestamps if we are equal or over the target.
- mFirstTargetMetTimestamp = 0;
- } else {
- // Set mFirstTargetMetTimestamp for first time meeting target.
- if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
- (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
- mFirstTargetMetTimestamp = now;
- }
- /**
- * Rate limit the change if the update is over mPreferredRateNanos since first
- * meeting target and less than mPreferredRateNanos since last meeting target.
- */
- if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
- now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
- return 0;
- }
- mLastTargetMetTimestamp = now;
- }
- binder::Status ret =
- mHintSession->reportActualWorkDuration(mActualDurationsNanos, mTimestampsNanos);
- if (!ret.isOk()) {
- ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
- ret.exceptionMessage().c_str());
- mFirstTargetMetTimestamp = 0;
- mLastTargetMetTimestamp = 0;
- return EPIPE;
- }
- mActualDurationsNanos.clear();
- mTimestampsNanos.clear();
+ WorkDuration workDuration(0, actualDurationNanos, actualDurationNanos, 0);
- return 0;
+ return reportActualWorkDurationInternal(&workDuration);
}
int APerformanceHintSession::sendHint(SessionHint hint) {
@@ -274,9 +247,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;
}
@@ -306,6 +280,79 @@ int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size
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;
+}
+
+int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* aWorkDuration) {
+ WorkDuration* workDuration = static_cast<WorkDuration*>(aWorkDuration);
+ if (workDuration->workPeriodStartTimestampNanos <= 0) {
+ ALOGE("%s: workPeriodStartTimestampNanos must be positive", __FUNCTION__);
+ return EINVAL;
+ }
+ if (workDuration->actualTotalDurationNanos <= 0) {
+ ALOGE("%s: actualDurationNanos must be positive", __FUNCTION__);
+ return EINVAL;
+ }
+ if (workDuration->actualCpuDurationNanos <= 0) {
+ ALOGE("%s: cpuDurationNanos must be positive", __FUNCTION__);
+ return EINVAL;
+ }
+ if (workDuration->actualGpuDurationNanos < 0) {
+ ALOGE("%s: gpuDurationNanos must be non negative", __FUNCTION__);
+ return EINVAL;
+ }
+
+ return reportActualWorkDurationInternal(workDuration);
+}
+
+int APerformanceHintSession::reportActualWorkDurationInternal(WorkDuration* workDuration) {
+ int64_t actualTotalDurationNanos = workDuration->actualTotalDurationNanos;
+ int64_t now = uptimeNanos();
+ workDuration->timestampNanos = now;
+ mActualWorkDurations.push_back(std::move(*workDuration));
+
+ if (actualTotalDurationNanos >= mTargetDurationNanos) {
+ // Reset timestamps if we are equal or over the target.
+ mFirstTargetMetTimestamp = 0;
+ } else {
+ // Set mFirstTargetMetTimestamp for first time meeting target.
+ if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
+ (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
+ mFirstTargetMetTimestamp = now;
+ }
+ /**
+ * Rate limit the change if the update is over mPreferredRateNanos since first
+ * meeting target and less than mPreferredRateNanos since last meeting target.
+ */
+ if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
+ now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
+ return 0;
+ }
+ mLastTargetMetTimestamp = now;
+ }
+
+ binder::Status ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
+ if (!ret.isOk()) {
+ ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
+ ret.exceptionMessage().c_str());
+ mFirstTargetMetTimestamp = 0;
+ mLastTargetMetTimestamp = 0;
+ return ret.exceptionCode() == binder::Status::EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
+ }
+ mActualWorkDurations.clear();
+
+ return 0;
+}
+
// ===================================== C API
APerformanceHintManager* APerformanceHint_getManager() {
return APerformanceHintManager::getInstance();
@@ -356,6 +403,68 @@ int APerformanceHint_getThreadIds(void* aPerformanceHintSession, int32_t* const
->getThreadIds(threadIds, size);
}
+int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) {
+ return session->setPreferPowerEfficiency(enabled);
+}
+
+int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session,
+ AWorkDuration* workDuration) {
+ if (session == nullptr || workDuration == nullptr) {
+ ALOGE("Invalid value: (session %p, workDuration %p)", session, workDuration);
+ return EINVAL;
+ }
+ return session->reportActualWorkDuration(workDuration);
+}
+
+AWorkDuration* AWorkDuration_create() {
+ WorkDuration* workDuration = new WorkDuration();
+ return static_cast<AWorkDuration*>(workDuration);
+}
+
+void AWorkDuration_release(AWorkDuration* aWorkDuration) {
+ if (aWorkDuration == nullptr) {
+ ALOGE("%s: aWorkDuration is nullptr", __FUNCTION__);
+ }
+ delete aWorkDuration;
+}
+
+void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* aWorkDuration,
+ int64_t workPeriodStartTimestampNanos) {
+ if (aWorkDuration == nullptr || workPeriodStartTimestampNanos <= 0) {
+ ALOGE("%s: Invalid value. (AWorkDuration: %p, workPeriodStartTimestampNanos: %" PRIi64 ")",
+ __FUNCTION__, aWorkDuration, workPeriodStartTimestampNanos);
+ }
+ static_cast<WorkDuration*>(aWorkDuration)->workPeriodStartTimestampNanos =
+ workPeriodStartTimestampNanos;
+}
+
+void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* aWorkDuration,
+ int64_t actualTotalDurationNanos) {
+ if (aWorkDuration == nullptr || actualTotalDurationNanos <= 0) {
+ ALOGE("%s: Invalid value. (AWorkDuration: %p, actualTotalDurationNanos: %" PRIi64 ")",
+ __FUNCTION__, aWorkDuration, actualTotalDurationNanos);
+ }
+ static_cast<WorkDuration*>(aWorkDuration)->actualTotalDurationNanos = actualTotalDurationNanos;
+}
+
+void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* aWorkDuration,
+ int64_t actualCpuDurationNanos) {
+ if (aWorkDuration == nullptr || actualCpuDurationNanos <= 0) {
+ ALOGE("%s: Invalid value. (AWorkDuration: %p, actualCpuDurationNanos: %" PRIi64 ")",
+ __FUNCTION__, aWorkDuration, actualCpuDurationNanos);
+ }
+ static_cast<WorkDuration*>(aWorkDuration)->actualCpuDurationNanos = actualCpuDurationNanos;
+}
+
+void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration,
+ int64_t actualGpuDurationNanos) {
+ if (aWorkDuration == nullptr || actualGpuDurationNanos < 0) {
+ ALOGE("%s: Invalid value. (AWorkDuration: %p, actualGpuDurationNanos: %" PRIi64 ")",
+ __FUNCTION__, aWorkDuration, actualGpuDurationNanos);
+ }
+ static_cast<WorkDuration*>(aWorkDuration)->actualGpuDurationNanos = actualGpuDurationNanos;
+}
+
void APerformanceHint_setIHintManagerForTesting(void* iManager) {
delete gHintManagerForTesting;
gHintManagerForTesting = nullptr;
diff --git a/native/android/system_fonts.cpp b/native/android/system_fonts.cpp
index ceab164aa324..91f78ce6f950 100644
--- a/native/android/system_fonts.cpp
+++ b/native/android/system_fonts.cpp
@@ -249,14 +249,15 @@ ASystemFontIterator* ASystemFontIterator_open() {
locale.emplace(minikin::getLocaleString(localeId));
}
std::vector<std::pair<uint32_t, float>> axes;
- for (const auto& [tag, value] : font->typeface()->GetAxes()) {
+ for (const auto& [tag, value] : font->baseTypeface()->GetAxes()) {
axes.push_back(std::make_pair(tag, value));
}
- fonts.insert({font->typeface()->GetFontPath(), std::move(locale),
+ fonts.insert({font->baseTypeface()->GetFontPath(), std::move(locale),
font->style().weight(),
font->style().slant() == minikin::FontStyle::Slant::ITALIC,
- static_cast<uint32_t>(font->typeface()->GetFontIndex()), axes});
+ static_cast<uint32_t>(font->baseTypeface()->GetFontIndex()),
+ axes});
}
});
@@ -321,7 +322,7 @@ AFont* _Nonnull AFontMatcher_match(
.font;
std::unique_ptr<AFont> result = std::make_unique<AFont>();
const android::MinikinFontSkia* minikinFontSkia =
- reinterpret_cast<android::MinikinFontSkia*>(font->typeface().get());
+ reinterpret_cast<android::MinikinFontSkia*>(font->baseTypeface().get());
result->mFilePath = minikinFontSkia->getFilePath();
result->mWeight = font->style().weight();
result->mItalic = font->style().slant() == minikin::FontStyle::Slant::ITALIC;
diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
index 791adfd33fcd..4553b4919d2d 100644
--- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
+++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "PerformanceHintNativeTest"
+#include <android/WorkDuration.h>
#include <android/os/IHintManager.h>
#include <android/os/IHintSession.h>
#include <android/performance_hint.h>
@@ -56,9 +57,12 @@ 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, 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));
+ MOCK_METHOD(Status, reportActualWorkDuration2,
+ (const ::std::vector<android::os::WorkDuration>& workDurations), (override));
};
class PerformanceHintTest : public Test {
@@ -119,6 +123,7 @@ TEST_F(PerformanceHintTest, TestSession) {
std::vector<int64_t> actualDurations;
actualDurations.push_back(20);
EXPECT_CALL(*iSession, reportActualWorkDuration(Eq(actualDurations), _)).Times(Exactly(1));
+ EXPECT_CALL(*iSession, reportActualWorkDuration2(_)).Times(Exactly(1));
result = APerformanceHint_reportActualWorkDuration(session, actualDurationNanos);
EXPECT_EQ(0, result);
@@ -178,4 +183,184 @@ 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);
+}
+
+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);
+}
+
+MATCHER_P(WorkDurationEq, expected, "") {
+ if (arg.size() != expected.size()) {
+ *result_listener << "WorkDuration vectors are different sizes. Expected: "
+ << expected.size() << ", Actual: " << arg.size();
+ return false;
+ }
+ for (int i = 0; i < expected.size(); ++i) {
+ android::os::WorkDuration expectedWorkDuration = expected[i];
+ android::os::WorkDuration actualWorkDuration = arg[i];
+ if (!expectedWorkDuration.equalsWithoutTimestamp(actualWorkDuration)) {
+ *result_listener << "WorkDuration at [" << i << "] is different: "
+ << "Expected: " << expectedWorkDuration
+ << ", Actual: " << actualWorkDuration;
+ return false;
+ }
+ }
+ return true;
+}
+
+TEST_F(PerformanceHintTest, TestAPerformanceHint_reportActualWorkDuration2) {
+ 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);
+
+ int64_t targetDurationNanos = 10;
+ EXPECT_CALL(*iSession, updateTargetWorkDuration(Eq(targetDurationNanos))).Times(Exactly(1));
+ int result = APerformanceHint_updateTargetWorkDuration(session, targetDurationNanos);
+ EXPECT_EQ(0, result);
+
+ usleep(2); // Sleep for longer than preferredUpdateRateNanos.
+ {
+ std::vector<android::os::WorkDuration> actualWorkDurations;
+ android::os::WorkDuration workDuration(1, 20, 13, 8);
+ actualWorkDurations.push_back(workDuration);
+
+ EXPECT_CALL(*iSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations)))
+ .Times(Exactly(1));
+ result = APerformanceHint_reportActualWorkDuration2(session,
+ static_cast<AWorkDuration*>(
+ &workDuration));
+ EXPECT_EQ(0, result);
+ }
+
+ {
+ std::vector<android::os::WorkDuration> actualWorkDurations;
+ android::os::WorkDuration workDuration(-1, 20, 13, 8);
+ actualWorkDurations.push_back(workDuration);
+
+ EXPECT_CALL(*iSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations)))
+ .Times(Exactly(1));
+ result = APerformanceHint_reportActualWorkDuration2(session,
+ static_cast<AWorkDuration*>(
+ &workDuration));
+ EXPECT_EQ(22, result);
+ }
+ {
+ std::vector<android::os::WorkDuration> actualWorkDurations;
+ android::os::WorkDuration workDuration(1, -20, 13, 8);
+ actualWorkDurations.push_back(workDuration);
+
+ EXPECT_CALL(*iSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations)))
+ .Times(Exactly(1));
+ result = APerformanceHint_reportActualWorkDuration2(session,
+ static_cast<AWorkDuration*>(
+ &workDuration));
+ EXPECT_EQ(22, result);
+ }
+ {
+ std::vector<android::os::WorkDuration> actualWorkDurations;
+ android::os::WorkDuration workDuration(1, 20, -13, 8);
+ actualWorkDurations.push_back(workDuration);
+
+ EXPECT_CALL(*iSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations)))
+ .Times(Exactly(1));
+ result = APerformanceHint_reportActualWorkDuration2(session,
+ static_cast<AWorkDuration*>(
+ &workDuration));
+ EXPECT_EQ(EINVAL, result);
+ }
+ {
+ std::vector<android::os::WorkDuration> actualWorkDurations;
+ android::os::WorkDuration workDuration(1, 20, 13, -8);
+ actualWorkDurations.push_back(workDuration);
+
+ EXPECT_CALL(*iSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations)))
+ .Times(Exactly(1));
+ result = APerformanceHint_reportActualWorkDuration2(session,
+ static_cast<AWorkDuration*>(
+ &workDuration));
+ EXPECT_EQ(EINVAL, result);
+ }
+
+ EXPECT_CALL(*iSession, close()).Times(Exactly(1));
+ APerformanceHint_closeSession(session);
+}
+
+TEST_F(PerformanceHintTest, TestAWorkDuration) {
+ AWorkDuration* aWorkDuration = AWorkDuration_create();
+ ASSERT_NE(aWorkDuration, nullptr);
+
+ AWorkDuration_setWorkPeriodStartTimestampNanos(aWorkDuration, 1);
+ AWorkDuration_setActualTotalDurationNanos(aWorkDuration, 20);
+ AWorkDuration_setActualCpuDurationNanos(aWorkDuration, 13);
+ AWorkDuration_setActualGpuDurationNanos(aWorkDuration, 8);
+ AWorkDuration_release(aWorkDuration);
}
diff --git a/native/android/tests/thermal/Android.bp b/native/android/tests/thermal/Android.bp
new file mode 100644
index 000000000000..8540d8327ada
--- /dev/null
+++ b/native/android/tests/thermal/Android.bp
@@ -0,0 +1,65 @@
+// Copyright (C) 2021 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+cc_test {
+ name: "NativeThermalUnitTestCases",
+
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+
+ srcs: ["NativeThermalUnitTest.cpp"],
+
+ shared_libs: [
+ "libandroid",
+ "liblog",
+ "libbinder",
+ "libpowermanager",
+ "libutils",
+ ],
+
+ static_libs: [
+ "libbase",
+ "libgmock",
+ "libgtest",
+ ],
+ stl: "c++_shared",
+
+ test_suites: [
+ "device-tests",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ header_libs: [
+ "libandroid_headers_private",
+ ],
+}
diff --git a/native/android/tests/thermal/NativeThermalUnitTest.cpp b/native/android/tests/thermal/NativeThermalUnitTest.cpp
new file mode 100644
index 000000000000..6d6861a3026a
--- /dev/null
+++ b/native/android/tests/thermal/NativeThermalUnitTest.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#define LOG_TAG "NativeThermalUnitTest"
+
+#include <android/os/IThermalService.h>
+#include <android/thermal.h>
+#include <binder/IBinder.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <thermal_private.h>
+
+using android::binder::Status;
+
+using namespace testing;
+using namespace android;
+using namespace android::os;
+
+class MockIThermalService : public IThermalService {
+public:
+ MOCK_METHOD(Status, registerThermalEventListener,
+ (const ::android::sp<::android::os::IThermalEventListener>& listener,
+ bool* _aidl_return),
+ (override));
+ MOCK_METHOD(Status, registerThermalEventListenerWithType,
+ (const ::android::sp<::android::os::IThermalEventListener>& listener, int32_t type,
+ bool* _aidl_return),
+ (override));
+ MOCK_METHOD(Status, unregisterThermalEventListener,
+ (const ::android::sp<::android::os::IThermalEventListener>& listener,
+ bool* _aidl_return),
+ (override));
+ MOCK_METHOD(Status, getCurrentTemperatures,
+ (::std::vector<::android::os::Temperature> * _aidl_return), (override));
+ MOCK_METHOD(Status, getCurrentTemperaturesWithType,
+ (int32_t type, ::std::vector<::android::os::Temperature>* _aidl_return),
+ (override));
+ MOCK_METHOD(Status, registerThermalStatusListener,
+ (const ::android::sp<::android::os::IThermalStatusListener>& listener,
+ bool* _aidl_return),
+ (override));
+ MOCK_METHOD(Status, unregisterThermalStatusListener,
+ (const ::android::sp<::android::os::IThermalStatusListener>& listener,
+ bool* _aidl_return),
+ (override));
+ MOCK_METHOD(Status, getCurrentThermalStatus, (int32_t * _aidl_return), (override));
+ MOCK_METHOD(Status, getCurrentCoolingDevices,
+ (::std::vector<::android::os::CoolingDevice> * _aidl_return), (override));
+ MOCK_METHOD(Status, getCurrentCoolingDevicesWithType,
+ (int32_t type, ::std::vector<::android::os::CoolingDevice>* _aidl_return),
+ (override));
+ MOCK_METHOD(Status, getThermalHeadroom, (int32_t forecastSeconds, float* _aidl_return),
+ (override));
+ MOCK_METHOD(Status, getThermalHeadroomThresholds, (::std::vector<float> * _aidl_return),
+ (override));
+ MOCK_METHOD(IBinder*, onAsBinder, (), (override));
+};
+
+class NativeThermalUnitTest : public Test {
+public:
+ void SetUp() override {
+ mMockIThermalService = new StrictMock<MockIThermalService>();
+ AThermal_setIThermalServiceForTesting(mMockIThermalService);
+ mThermalManager = AThermal_acquireManager();
+ }
+
+ void TearDown() override {
+ AThermal_setIThermalServiceForTesting(nullptr);
+ AThermal_releaseManager(mThermalManager);
+ }
+
+ StrictMock<MockIThermalService>* mMockIThermalService = nullptr;
+ AThermalManager* mThermalManager = nullptr;
+};
+
+static void checkThermalHeadroomThresholds(const std::vector<float>& expected,
+ const AThermalHeadroomThreshold* thresholds,
+ size_t size) {
+ if (thresholds == nullptr) {
+ FAIL() << "Unexpected null thresholds pointer";
+ }
+ for (int i = 0; i < (int)size; i++) {
+ auto t = thresholds[i];
+ ASSERT_EQ(i, t.thermalStatus) << "threshold " << i << " should have status " << i;
+ ASSERT_EQ(expected[i], t.headroom)
+ << "threshold " << i << " should have headroom " << expected[i];
+ }
+}
+
+TEST_F(NativeThermalUnitTest, TestGetThermalHeadroomThresholds) {
+ std::vector<float> expected = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+ EXPECT_CALL(*mMockIThermalService, getThermalHeadroomThresholds(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(expected), Return(Status())));
+ const AThermalHeadroomThreshold* thresholds1 = nullptr;
+ size_t size1;
+ ASSERT_EQ(OK, AThermal_getThermalHeadroomThresholds(mThermalManager, &thresholds1, &size1));
+ checkThermalHeadroomThresholds(expected, thresholds1, size1);
+ // following calls should be cached
+ EXPECT_CALL(*mMockIThermalService, getThermalHeadroomThresholds(_)).Times(0);
+
+ const AThermalHeadroomThreshold* thresholds2 = nullptr;
+ size_t size2;
+ ASSERT_EQ(OK, AThermal_getThermalHeadroomThresholds(mThermalManager, &thresholds2, &size2));
+ checkThermalHeadroomThresholds(expected, thresholds2, size2);
+}
+
+TEST_F(NativeThermalUnitTest, TestGetThermalHeadroomThresholdsFailedWithServerError) {
+ const AThermalHeadroomThreshold* thresholds = nullptr;
+ size_t size;
+ EXPECT_CALL(*mMockIThermalService, getThermalHeadroomThresholds(_))
+ .Times(Exactly(1))
+ .WillOnce(Return(
+ Status::fromExceptionCode(binder::Status::Exception::EX_ILLEGAL_ARGUMENT)));
+ ASSERT_EQ(EPIPE, AThermal_getThermalHeadroomThresholds(mThermalManager, &thresholds, &size));
+ ASSERT_EQ(nullptr, thresholds);
+}
+
+TEST_F(NativeThermalUnitTest, TestGetThermalHeadroomThresholdsFailedWithFeatureDisabled) {
+ const AThermalHeadroomThreshold* thresholds = nullptr;
+ size_t size;
+ EXPECT_CALL(*mMockIThermalService, getThermalHeadroomThresholds(_))
+ .Times(Exactly(1))
+ .WillOnce(Return(Status::fromExceptionCode(
+ binder::Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ ASSERT_EQ(ENOSYS, AThermal_getThermalHeadroomThresholds(mThermalManager, &thresholds, &size));
+ ASSERT_EQ(nullptr, thresholds);
+}
+
+TEST_F(NativeThermalUnitTest, TestGetThermalHeadroomThresholdsFailedWithNullPtr) {
+ const AThermalHeadroomThreshold* thresholds = nullptr;
+ size_t size;
+ size_t* nullSize = nullptr;
+ ASSERT_EQ(EINVAL,
+ AThermal_getThermalHeadroomThresholds(mThermalManager, &thresholds, nullSize));
+ ASSERT_EQ(nullptr, thresholds);
+ ASSERT_EQ(EINVAL, AThermal_getThermalHeadroomThresholds(mThermalManager, nullptr, &size));
+}
+
+TEST_F(NativeThermalUnitTest, TestGetThermalHeadroomThresholdsFailedWithNonEmptyPtr) {
+ const AThermalHeadroomThreshold* initialized = new AThermalHeadroomThreshold[1];
+ size_t size;
+ ASSERT_EQ(EINVAL, AThermal_getThermalHeadroomThresholds(mThermalManager, &initialized, &size));
+ delete[] initialized;
+}
diff --git a/native/android/tests/thermal/OWNERS b/native/android/tests/thermal/OWNERS
new file mode 100644
index 000000000000..e3bbee92057d
--- /dev/null
+++ b/native/android/tests/thermal/OWNERS
@@ -0,0 +1 @@
+include /ADPF_OWNERS
diff --git a/native/android/thermal.cpp b/native/android/thermal.cpp
index 1f6ef4755aff..b43f2f16a7cb 100644
--- a/native/android/thermal.cpp
+++ b/native/android/thermal.cpp
@@ -16,27 +16,32 @@
#define LOG_TAG "thermal"
-#include <cerrno>
-#include <thread>
-#include <limits>
-
-#include <android/thermal.h>
+#include <android-base/thread_annotations.h>
#include <android/os/BnThermalStatusListener.h>
#include <android/os/IThermalService.h>
+#include <android/thermal.h>
#include <binder/IServiceManager.h>
+#include <thermal_private.h>
#include <utils/Log.h>
+#include <cerrno>
+#include <limits>
+#include <thread>
+
using android::sp;
using namespace android;
using namespace android::os;
struct ThermalServiceListener : public BnThermalStatusListener {
- public:
- virtual binder::Status onStatusChange(int32_t status) override;
- ThermalServiceListener(AThermalManager *manager) {mMgr = manager;}
- private:
- AThermalManager *mMgr;
+public:
+ virtual binder::Status onStatusChange(int32_t status) override;
+ ThermalServiceListener(AThermalManager *manager) {
+ mMgr = manager;
+ }
+
+private:
+ AThermalManager *mMgr;
};
struct ListenerCallback {
@@ -44,22 +49,29 @@ struct ListenerCallback {
void* data;
};
+static IThermalService *gIThermalServiceForTesting = nullptr;
+
struct AThermalManager {
- public:
- static AThermalManager* createAThermalManager();
- AThermalManager() = delete;
- ~AThermalManager();
- status_t notifyStateChange(int32_t status);
- status_t getCurrentThermalStatus(int32_t *status);
- status_t addListener(AThermal_StatusCallback, void *data);
- status_t removeListener(AThermal_StatusCallback, void *data);
- status_t getThermalHeadroom(int32_t forecastSeconds, float *result);
- private:
- AThermalManager(sp<IThermalService> service);
- sp<IThermalService> mThermalSvc;
- sp<ThermalServiceListener> mServiceListener;
- std::vector<ListenerCallback> mListeners;
- std::mutex mMutex;
+public:
+ static AThermalManager *createAThermalManager();
+ AThermalManager() = delete;
+ ~AThermalManager();
+ status_t notifyStateChange(int32_t status);
+ status_t getCurrentThermalStatus(int32_t *status);
+ status_t addListener(AThermal_StatusCallback, void *data);
+ status_t removeListener(AThermal_StatusCallback, void *data);
+ status_t getThermalHeadroom(int32_t forecastSeconds, float *result);
+ status_t getThermalHeadroomThresholds(const AThermalHeadroomThreshold **, size_t *size);
+
+private:
+ AThermalManager(sp<IThermalService> service);
+ sp<IThermalService> mThermalSvc;
+ std::mutex mListenerMutex;
+ sp<ThermalServiceListener> mServiceListener GUARDED_BY(mListenerMutex);
+ std::vector<ListenerCallback> mListeners GUARDED_BY(mListenerMutex);
+ std::mutex mThresholdsMutex;
+ const AThermalHeadroomThreshold *mThresholds = nullptr; // GUARDED_BY(mThresholdsMutex)
+ size_t mThresholdsCount GUARDED_BY(mThresholdsMutex);
};
binder::Status ThermalServiceListener::onStatusChange(int32_t status) {
@@ -70,6 +82,9 @@ binder::Status ThermalServiceListener::onStatusChange(int32_t status) {
}
AThermalManager* AThermalManager::createAThermalManager() {
+ if (gIThermalServiceForTesting) {
+ return new AThermalManager(gIThermalServiceForTesting);
+ }
sp<IBinder> binder =
defaultServiceManager()->checkService(String16("thermalservice"));
@@ -81,12 +96,10 @@ AThermalManager* AThermalManager::createAThermalManager() {
}
AThermalManager::AThermalManager(sp<IThermalService> service)
- : mThermalSvc(service),
- mServiceListener(nullptr) {
-}
+ : mThermalSvc(std::move(service)), mServiceListener(nullptr) {}
AThermalManager::~AThermalManager() {
- std::unique_lock<std::mutex> lock(mMutex);
+ std::unique_lock<std::mutex> listenerLock(mListenerMutex);
mListeners.clear();
if (mServiceListener != nullptr) {
@@ -94,10 +107,13 @@ AThermalManager::~AThermalManager() {
mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success);
mServiceListener = nullptr;
}
+ listenerLock.unlock();
+ std::unique_lock<std::mutex> lock(mThresholdsMutex);
+ delete[] mThresholds;
}
status_t AThermalManager::notifyStateChange(int32_t status) {
- std::unique_lock<std::mutex> lock(mMutex);
+ std::unique_lock<std::mutex> lock(mListenerMutex);
AThermalStatus thermalStatus = static_cast<AThermalStatus>(status);
for (auto listener : mListeners) {
@@ -107,7 +123,7 @@ status_t AThermalManager::notifyStateChange(int32_t status) {
}
status_t AThermalManager::addListener(AThermal_StatusCallback callback, void *data) {
- std::unique_lock<std::mutex> lock(mMutex);
+ std::unique_lock<std::mutex> lock(mListenerMutex);
if (callback == nullptr) {
// Callback can not be nullptr
@@ -141,7 +157,7 @@ status_t AThermalManager::addListener(AThermal_StatusCallback callback, void *da
}
status_t AThermalManager::removeListener(AThermal_StatusCallback callback, void *data) {
- std::unique_lock<std::mutex> lock(mMutex);
+ std::unique_lock<std::mutex> lock(mListenerMutex);
auto it = std::remove_if(mListeners.begin(),
mListeners.end(),
@@ -198,6 +214,32 @@ status_t AThermalManager::getThermalHeadroom(int32_t forecastSeconds, float *res
return OK;
}
+status_t AThermalManager::getThermalHeadroomThresholds(const AThermalHeadroomThreshold **result,
+ size_t *size) {
+ std::unique_lock<std::mutex> lock(mThresholdsMutex);
+ if (mThresholds == nullptr) {
+ auto thresholds = std::make_unique<std::vector<float>>();
+ binder::Status ret = mThermalSvc->getThermalHeadroomThresholds(thresholds.get());
+ if (!ret.isOk()) {
+ if (ret.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) {
+ // feature is not enabled
+ return ENOSYS;
+ }
+ return EPIPE;
+ }
+ mThresholdsCount = thresholds->size();
+ auto t = new AThermalHeadroomThreshold[mThresholdsCount];
+ for (int i = 0; i < (int)mThresholdsCount; i++) {
+ t[i].headroom = (*thresholds)[i];
+ t[i].thermalStatus = static_cast<AThermalStatus>(i);
+ }
+ mThresholds = t;
+ }
+ *size = mThresholdsCount;
+ *result = mThresholds;
+ return OK;
+}
+
/**
* Acquire an instance of the thermal manager. This must be freed using
* {@link AThermal_releaseManager}.
@@ -291,14 +333,24 @@ int AThermal_unregisterThermalStatusListener(AThermalManager *manager,
* threshold. Returns NaN if the device does not support this functionality or if
* this function is called significantly faster than once per second.
*/
-float AThermal_getThermalHeadroom(AThermalManager *manager,
- int forecastSeconds) {
+float AThermal_getThermalHeadroom(AThermalManager *manager, int forecastSeconds) {
float result = 0.0f;
status_t ret = manager->getThermalHeadroom(forecastSeconds, &result);
-
if (ret != OK) {
result = std::numeric_limits<float>::quiet_NaN();
}
-
return result;
}
+
+int AThermal_getThermalHeadroomThresholds(AThermalManager *manager,
+ const AThermalHeadroomThreshold **outThresholds,
+ size_t *size) {
+ if (outThresholds == nullptr || *outThresholds != nullptr || size == nullptr) {
+ return EINVAL;
+ }
+ return manager->getThermalHeadroomThresholds(outThresholds, size);
+}
+
+void AThermal_setIThermalServiceForTesting(void *iThermalService) {
+ gIThermalServiceForTesting = static_cast<IThermalService *>(iThermalService);
+}
diff --git a/native/webview/TEST_MAPPING b/native/webview/TEST_MAPPING
index c1bc6d720ece..07f438329e43 100644
--- a/native/webview/TEST_MAPPING
+++ b/native/webview/TEST_MAPPING
@@ -26,6 +26,7 @@
},
{
"name": "GtsWebViewTestCases",
+ "keywords": ["internal"],
"options": [
{
"exclude-annotation": "android.test.FlakyTest"
@@ -34,6 +35,7 @@
},
{
"name": "GtsWebViewHostTestCases",
+ "keywords": ["internal"],
"options": [
{
"exclude-annotation": "android.test.FlakyTest"