blob: 066e773da428d0d484d653613f6d42bb1407e010 [file] [log] [blame]
Peiyong Lin56960752022-09-30 21:52:52 +00001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <algorithm>
18#include <chrono>
19#include <cmath>
20#include <memory>
21#include <string>
22#include <thread>
Xiang Wange88a10c2023-09-12 17:29:38 -070023#include <unordered_map>
Peiyong Lin56960752022-09-30 21:52:52 +000024#include <vector>
25
26#define LOG_TAG "thermal_aidl_hal_test"
27
Xiang Wang5eb4c732024-04-12 17:38:09 -070028#include <VtsCoreUtil.h>
Peiyong Lin56960752022-09-30 21:52:52 +000029#include <aidl/Gtest.h>
30#include <aidl/Vintf.h>
TeYuan Wang2bbd1ec2023-12-11 14:55:39 -080031#include <aidl/android/hardware/thermal/BnCoolingDeviceChangedCallback.h>
Peiyong Lin56960752022-09-30 21:52:52 +000032#include <aidl/android/hardware/thermal/BnThermal.h>
33#include <aidl/android/hardware/thermal/BnThermalChangedCallback.h>
34#include <android-base/logging.h>
35#include <android-base/properties.h>
36#include <android/binder_ibinder.h>
37#include <android/binder_interface_utils.h>
38#include <android/binder_manager.h>
39#include <android/binder_process.h>
40#include <android/binder_status.h>
41#include <gtest/gtest.h>
42
43#include <unistd.h>
44
45namespace aidl::android::hardware::thermal {
46
47namespace {
48
49using ::android::sp;
50using android::hardware::thermal::CoolingDevice;
51using android::hardware::thermal::IThermal;
52using android::hardware::thermal::Temperature;
53using android::hardware::thermal::TemperatureType;
54
55using namespace std::string_literals;
56using namespace std::chrono_literals;
57
58static const Temperature kThrottleTemp = {
59 .type = TemperatureType::SKIN,
60 .name = "test temperature sensor",
61 .value = 98.6,
62 .throttlingStatus = ThrottlingSeverity::CRITICAL,
63};
64
TeYuan Wang2bbd1ec2023-12-11 14:55:39 -080065static const CoolingDevice kCoolingDevice = {
66 .type = CoolingType::CPU,
67 .name = "test cooling device",
68 .value = 1,
69 .powerLimitMw = 300,
70 .powerMw = 500,
71 .timeWindowMs = 7000,
72};
73
Xiang Wang5eb4c732024-04-12 17:38:09 -070074static const std::string FEATURE_WATCH = "android.hardware.type.watch";
75static const std::string FEATURE_TELEVISION = "android.hardware.type.television";
76static const std::string FEATURE_LEANBACK = "android.software.leanback";
77static const std::string FEATURE_AUTOMOTIVE = "android.hardware.type.automotive";
78static const std::string FEATURE_PC = "android.hardware.type.pc";
79static const std::string FEATURE_EMBEDDED = "android.hardware.type.embedded";
80static const std::string kNonHandheldFeatures[] = {FEATURE_AUTOMOTIVE, FEATURE_LEANBACK,
81 FEATURE_PC, FEATURE_TELEVISION,
82 FEATURE_WATCH, FEATURE_EMBEDDED};
83
Peiyong Lin56960752022-09-30 21:52:52 +000084// Callback class for receiving thermal event notifications from main class
85class ThermalCallback : public BnThermalChangedCallback {
86 public:
87 ndk::ScopedAStatus notifyThrottling(const Temperature&) override {
88 {
89 std::lock_guard<std::mutex> lock(mMutex);
90 mInvoke = true;
91 }
92 mNotifyThrottling.notify_all();
93 return ndk::ScopedAStatus::ok();
94 }
95
Xiang Wangbd4ef072024-09-20 16:24:22 -070096 ndk::ScopedAStatus notifyThresholdChanged(const TemperatureThreshold&) {
97 return ndk::ScopedAStatus::ok();
98 }
99
Peiyong Lin56960752022-09-30 21:52:52 +0000100 template <typename R, typename P>
101 [[nodiscard]] bool waitForCallback(std::chrono::duration<R, P> duration) {
102 std::unique_lock<std::mutex> lock(mMutex);
103 bool r = mNotifyThrottling.wait_for(lock, duration, [this] { return this->mInvoke; });
104 mInvoke = false;
105 return r;
106 }
107
108 private:
109 std::mutex mMutex;
110 std::condition_variable mNotifyThrottling;
111 bool mInvoke = false;
112};
113
TeYuan Wang2bbd1ec2023-12-11 14:55:39 -0800114// Callback class for receiving cooling device event notifications from main class
115class CoolingDeviceCallback : public BnCoolingDeviceChangedCallback {
116 public:
117 ndk::ScopedAStatus notifyCoolingDeviceChanged(const CoolingDevice&) override {
118 {
119 std::lock_guard<std::mutex> lock(mMutex);
120 mInvoke = true;
121 }
122 mNotifyCoolingDeviceChanged.notify_all();
123 return ndk::ScopedAStatus::ok();
124 }
125
126 template <typename R, typename P>
127 [[nodiscard]] bool waitForCallback(std::chrono::duration<R, P> duration) {
128 std::unique_lock<std::mutex> lock(mMutex);
129 bool r = mNotifyCoolingDeviceChanged.wait_for(lock, duration,
130 [this] { return this->mInvoke; });
131 mInvoke = false;
132 return r;
133 }
134
135 private:
136 std::mutex mMutex;
137 std::condition_variable mNotifyCoolingDeviceChanged;
138 bool mInvoke = false;
139};
140
Peiyong Lin56960752022-09-30 21:52:52 +0000141// The main test class for THERMAL HIDL HAL.
142class ThermalAidlTest : public testing::TestWithParam<std::string> {
143 public:
144 void SetUp() override {
145 AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
146 ASSERT_NE(binder, nullptr);
147 mThermal = IThermal::fromBinder(ndk::SpAIBinder(binder));
148
149 mThermalCallback = ndk::SharedRefBase::make<ThermalCallback>();
150 ASSERT_NE(mThermalCallback, nullptr);
Xiang Wange7b177e2022-12-21 17:55:11 -0800151 ::ndk::ScopedAStatus status = mThermal->registerThermalChangedCallback(mThermalCallback);
152 ASSERT_TRUE(status.isOk()) << status.getMessage();
TeYuan Wang2bbd1ec2023-12-11 14:55:39 -0800153
154 auto ret = mThermal->getInterfaceVersion(&thermal_version);
155 ASSERT_TRUE(ret.isOk()) << ret;
156 if (thermal_version > 1) {
157 mCoolingDeviceCallback = ndk::SharedRefBase::make<CoolingDeviceCallback>();
158 ASSERT_NE(mCoolingDeviceCallback, nullptr);
159 status = mThermal->registerCoolingDeviceChangedCallbackWithType(mCoolingDeviceCallback,
160 kCoolingDevice.type);
161 ASSERT_TRUE(status.isOk()) << status.getMessage();
162 }
Peiyong Lin56960752022-09-30 21:52:52 +0000163 }
164
165 void TearDown() override {
Xiang Wange7b177e2022-12-21 17:55:11 -0800166 ::ndk::ScopedAStatus status = mThermal->unregisterThermalChangedCallback(mThermalCallback);
167 ASSERT_TRUE(status.isOk()) << status.getMessage();
TeYuan Wang2bbd1ec2023-12-11 14:55:39 -0800168
Peiyong Lin56960752022-09-30 21:52:52 +0000169 // Expect to fail if unregister again
Xiang Wangd43e8732023-02-07 12:10:33 -0800170 status = mThermal->unregisterThermalChangedCallback(mThermalCallback);
Xiang Wangd43e8732023-02-07 12:10:33 -0800171 ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
TeYuan Wang2bbd1ec2023-12-11 14:55:39 -0800172
173 auto ret = mThermal->getInterfaceVersion(&thermal_version);
174 ASSERT_TRUE(ret.isOk()) << ret;
175 if (thermal_version > 1) {
176 status = mThermal->unregisterCoolingDeviceChangedCallback(mCoolingDeviceCallback);
177 ASSERT_TRUE(status.isOk()) << status.getMessage();
178 status = mThermal->unregisterCoolingDeviceChangedCallback(mCoolingDeviceCallback);
179 ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
180 }
Peiyong Lin56960752022-09-30 21:52:52 +0000181 }
TeYuan Wang2bbd1ec2023-12-11 14:55:39 -0800182 // Stores thermal version
183 int32_t thermal_version;
Peiyong Lin56960752022-09-30 21:52:52 +0000184
185 protected:
186 std::shared_ptr<IThermal> mThermal;
187 std::shared_ptr<ThermalCallback> mThermalCallback;
TeYuan Wang2bbd1ec2023-12-11 14:55:39 -0800188 std::shared_ptr<CoolingDeviceCallback> mCoolingDeviceCallback;
Peiyong Lin56960752022-09-30 21:52:52 +0000189};
190
191// Test ThermalChangedCallback::notifyThrottling().
192// This just calls into and back from our local ThermalChangedCallback impl.
193TEST_P(ThermalAidlTest, NotifyThrottlingTest) {
194 std::shared_ptr<ThermalCallback> thermalCallback = ndk::SharedRefBase::make<ThermalCallback>();
Xiang Wange7b177e2022-12-21 17:55:11 -0800195 ::ndk::ScopedAStatus status = thermalCallback->notifyThrottling(kThrottleTemp);
196 ASSERT_TRUE(status.isOk()) << status.getMessage();
Peiyong Lin56960752022-09-30 21:52:52 +0000197 ASSERT_TRUE(thermalCallback->waitForCallback(200ms));
198}
199
TeYuan Wang2bbd1ec2023-12-11 14:55:39 -0800200// Test CoolingDeviceChangedCallback::notifyCoolingDeviceChanged().
201// This just calls into and back from our local CoolingDeviceChangedCallback impl.
202TEST_P(ThermalAidlTest, NotifyCoolingDeviceChangedTest) {
203 auto ret = mThermal->getInterfaceVersion(&thermal_version);
204 ASSERT_TRUE(ret.isOk()) << ret;
205 if (thermal_version < 2) {
206 return;
207 }
208 std::shared_ptr<CoolingDeviceCallback> cdevCallback =
209 ndk::SharedRefBase::make<CoolingDeviceCallback>();
210 ::ndk::ScopedAStatus status = cdevCallback->notifyCoolingDeviceChanged(kCoolingDevice);
211 ASSERT_TRUE(status.isOk()) << status.getMessage();
212 ASSERT_TRUE(cdevCallback->waitForCallback(200ms));
213}
214
Xiang Wange7b177e2022-12-21 17:55:11 -0800215// Test Thermal->registerThermalChangedCallback.
216TEST_P(ThermalAidlTest, RegisterThermalChangedCallbackTest) {
217 // Expect to fail with same callback
218 ::ndk::ScopedAStatus status = mThermal->registerThermalChangedCallback(mThermalCallback);
219 ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
220 // Expect to fail with null callback
221 status = mThermal->registerThermalChangedCallback(nullptr);
Sean Dooher3869fa62023-06-12 20:14:00 +0000222 ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT
223 || status.getExceptionCode() == EX_NULL_POINTER);
Xiang Wange7b177e2022-12-21 17:55:11 -0800224 std::shared_ptr<ThermalCallback> localThermalCallback =
225 ndk::SharedRefBase::make<ThermalCallback>();
226 // Expect to succeed with different callback
227 status = mThermal->registerThermalChangedCallback(localThermalCallback);
228 ASSERT_TRUE(status.isOk()) << status.getMessage();
Xiang Wange7b177e2022-12-21 17:55:11 -0800229 // Remove the local callback
230 status = mThermal->unregisterThermalChangedCallback(localThermalCallback);
231 ASSERT_TRUE(status.isOk()) << status.getMessage();
232 // Expect to fail with null callback
233 status = mThermal->unregisterThermalChangedCallback(nullptr);
Sean Dooher3869fa62023-06-12 20:14:00 +0000234 ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT
235 || status.getExceptionCode() == EX_NULL_POINTER);
Xiang Wange7b177e2022-12-21 17:55:11 -0800236}
237
238// Test Thermal->registerThermalChangedCallbackWithType.
239TEST_P(ThermalAidlTest, RegisterThermalChangedCallbackWithTypeTest) {
240 // Expect to fail with same callback
241 ::ndk::ScopedAStatus status = mThermal->registerThermalChangedCallbackWithType(
242 mThermalCallback, TemperatureType::SKIN);
243 ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
244 // Expect to fail with null callback
245 status = mThermal->registerThermalChangedCallbackWithType(nullptr, TemperatureType::SKIN);
Sean Dooher3869fa62023-06-12 20:14:00 +0000246 ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT
247 || status.getExceptionCode() == EX_NULL_POINTER);
Xiang Wange7b177e2022-12-21 17:55:11 -0800248 std::shared_ptr<ThermalCallback> localThermalCallback =
249 ndk::SharedRefBase::make<ThermalCallback>();
250 // Expect to succeed with different callback
251 status = mThermal->registerThermalChangedCallbackWithType(localThermalCallback,
252 TemperatureType::SKIN);
253 ASSERT_TRUE(status.isOk()) << status.getMessage();
Xiang Wange7b177e2022-12-21 17:55:11 -0800254 // Remove the local callback
255 status = mThermal->unregisterThermalChangedCallback(localThermalCallback);
256 ASSERT_TRUE(status.isOk()) << status.getMessage();
257 // Expect to fail with null callback
258 status = mThermal->unregisterThermalChangedCallback(nullptr);
Sean Dooher3869fa62023-06-12 20:14:00 +0000259 ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT
260 || status.getExceptionCode() == EX_NULL_POINTER);
Xiang Wange7b177e2022-12-21 17:55:11 -0800261}
262
TeYuan Wang2bbd1ec2023-12-11 14:55:39 -0800263// Test Thermal->registerCoolingDeviceChangedCallbackWithType.
264TEST_P(ThermalAidlTest, RegisterCoolingDeviceChangedCallbackWithTypeTest) {
265 auto ret = mThermal->getInterfaceVersion(&thermal_version);
266 ASSERT_TRUE(ret.isOk()) << ret;
267 if (thermal_version < 2) {
268 return;
269 }
270
271 // Expect to fail with same callback
272 ::ndk::ScopedAStatus status = mThermal->registerCoolingDeviceChangedCallbackWithType(
273 mCoolingDeviceCallback, CoolingType::CPU);
274 ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
275 // Expect to fail with null callback
276 status = mThermal->registerCoolingDeviceChangedCallbackWithType(nullptr, CoolingType::CPU);
277 ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT ||
278 status.getExceptionCode() == EX_NULL_POINTER);
279 std::shared_ptr<CoolingDeviceCallback> localCoolingDeviceCallback =
280 ndk::SharedRefBase::make<CoolingDeviceCallback>();
281 // Expect to succeed with different callback
282 status = mThermal->registerCoolingDeviceChangedCallbackWithType(localCoolingDeviceCallback,
283 CoolingType::CPU);
284 ASSERT_TRUE(status.isOk()) << status.getMessage();
285 // Remove the local callback
286 status = mThermal->unregisterCoolingDeviceChangedCallback(localCoolingDeviceCallback);
287 ASSERT_TRUE(status.isOk()) << status.getMessage();
288 // Expect to fail with null callback
289 status = mThermal->unregisterCoolingDeviceChangedCallback(nullptr);
290 ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT ||
291 status.getExceptionCode() == EX_NULL_POINTER);
292}
293
Xiang Wange7b177e2022-12-21 17:55:11 -0800294// Test Thermal->getCurrentTemperatures().
295TEST_P(ThermalAidlTest, TemperatureTest) {
296 std::vector<Temperature> ret;
297 ::ndk::ScopedAStatus status = mThermal->getTemperatures(&ret);
298 if (status.isOk()) {
299 for (auto& i : ret) {
300 EXPECT_LT(0u, i.name.size());
301 LOG(INFO) << i.name + " " + toString(i.type) << "\n";
302 }
303 } else {
304 ASSERT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode());
305 }
306
307 auto types = ::ndk::enum_range<TemperatureType>();
308 for (const auto& type : types) {
309 status = mThermal->getTemperaturesWithType(type, &ret);
310
311 if (status.isOk()) {
312 for (auto& i : ret) {
313 EXPECT_EQ(type, i.type) << "Expect type " + toString(type) + " but got " +
314 toString(i.type) + " for " + i.name;
315 EXPECT_LT(0u, i.name.size());
316 }
317 } else {
318 ASSERT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode());
319 }
320 }
321}
322
323// Test Thermal->getTemperatureThresholds().
324TEST_P(ThermalAidlTest, TemperatureThresholdTest) {
325 std::vector<TemperatureThreshold> ret;
326 ::ndk::ScopedAStatus status = mThermal->getTemperatureThresholds(&ret);
327 if (status.isOk()) {
328 for (auto& i : ret) {
329 EXPECT_LT(0u, i.name.size());
330 LOG(INFO) << i.name + " " + toString(i.type) << "\n";
331 }
332 } else {
333 ASSERT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode());
334 }
335
336 auto types = ::ndk::enum_range<TemperatureType>();
337 for (const auto& type : types) {
338 status = mThermal->getTemperatureThresholdsWithType(type, &ret);
339
340 if (status.isOk()) {
341 for (auto& i : ret) {
342 EXPECT_EQ(type, i.type) << "Expect type " + toString(type) + " but got " +
343 toString(i.type) + " for " + i.name;
344 EXPECT_LT(0u, i.name.size());
345 }
346 } else {
347 ASSERT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode());
348 }
349 }
350}
351
Xiang Wange88a10c2023-09-12 17:29:38 -0700352// Test Thermal->getTemperatureThresholdsWithType(SKIN).
353// @VsrTest = GMS-VSR-3.2.5-001
354// @VsrTest = VSR-3.2.5-001
355// @VsrTest = GMS-VSR-3.2.5-002
356// @VsrTest = VSR-3.2.5-002
357TEST_P(ThermalAidlTest, SkinTemperatureThresholdsTest) {
358 auto apiLevel = ::android::base::GetIntProperty<int32_t>("ro.vendor.api_level", 0);
Xiang Wang51016462024-06-05 18:04:34 +0000359 if (apiLevel < 202404) {
360 GTEST_SKIP() << "Skipping test as the vendor level is below 202404: " << apiLevel;
Xiang Wange88a10c2023-09-12 17:29:38 -0700361 }
Xiang Wang5eb4c732024-04-12 17:38:09 -0700362 for (const auto& feature : kNonHandheldFeatures) {
363 if (::testing::deviceSupportsFeature(feature.c_str())) {
364 GTEST_SKIP() << "Skipping test as the device has feature: " << feature;
365 }
366 }
Xiang Wange88a10c2023-09-12 17:29:38 -0700367 std::vector<Temperature> temperatures;
368 ::ndk::ScopedAStatus status =
369 mThermal->getTemperaturesWithType(TemperatureType::SKIN, &temperatures);
370 ASSERT_TRUE(status.isOk()) << "getTemperaturesWithType(SKIN) failed";
371 ASSERT_FALSE(temperatures.empty()) << "getTemperaturesWithType(SKIN) returns empty";
372 ASSERT_EQ(1, temperatures.size())
373 << "getTemperaturesWithType(SKIN) returns multiple temperatures";
374
375 std::vector<TemperatureThreshold> thresholds;
376 status = mThermal->getTemperatureThresholdsWithType(TemperatureType::SKIN, &thresholds);
377 ASSERT_TRUE(status.isOk()) << "getTemperatureThresholdsWithType(SKIN) failed";
378 ASSERT_FALSE(thresholds.empty()) << "getTemperatureThresholdsWithType(SKIN) returns empty";
379 ASSERT_EQ(1, thresholds.size())
380 << "getTemperatureThresholdsWithType(SKIN) returns multiple thresholds";
381 auto temperature = temperatures[0];
382 auto threshold = thresholds[0];
383 ASSERT_EQ(temperature.name, threshold.name);
384 auto severities = ::ndk::enum_range<ThrottlingSeverity>();
385 auto cardinality = std::distance(severities.begin(), severities.end());
386 ASSERT_NE(NAN, temperature.value);
387 ASSERT_EQ(cardinality, threshold.hotThrottlingThresholds.size());
388 float lastThreshold = threshold.hotThrottlingThresholds[1];
389 // skip NONE, and check that the rest should be set and non-decreasing
390 for (auto i = 2; i < cardinality; i++) {
391 float t = threshold.hotThrottlingThresholds[i];
392 ASSERT_NE(NAN, t);
393 ASSERT_TRUE(t >= lastThreshold) << "Temperature thresholds should be non-decreasing "
394 << "but got " << t << " for status " << i << " and "
395 << lastThreshold << " for status " << i - 1;
396 lastThreshold = t;
397 }
398}
399
Xiang Wange7b177e2022-12-21 17:55:11 -0800400// Test Thermal->getCoolingDevices().
401TEST_P(ThermalAidlTest, CoolingDeviceTest) {
402 std::vector<CoolingDevice> ret;
403 ::ndk::ScopedAStatus status = mThermal->getCoolingDevices(&ret);
404 if (status.isOk()) {
405 for (auto& i : ret) {
406 EXPECT_LT(0u, i.name.size());
407 LOG(INFO) << i.name + " " + toString(i.type) << "\n";
408 }
409 } else {
410 ASSERT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode());
411 }
412
413 auto types = ::ndk::enum_range<CoolingType>();
414 for (const auto& type : types) {
415 status = mThermal->getCoolingDevicesWithType(type, &ret);
416 if (status.isOk()) {
417 ASSERT_TRUE(status.isOk());
418 for (auto& i : ret) {
419 EXPECT_EQ(type, i.type) << "Expect type " + toString(type) + " but got " +
420 toString(i.type) + " for " + i.name;
421 EXPECT_LT(0u, i.name.size());
422 }
423 } else {
424 ASSERT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode());
425 }
426 }
427}
428
Peiyong Lin56960752022-09-30 21:52:52 +0000429GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ThermalAidlTest);
430INSTANTIATE_TEST_SUITE_P(
431 Thermal, ThermalAidlTest,
432 testing::ValuesIn(::android::getAidlHalInstanceNames(IThermal::descriptor)),
433 ::android::PrintInstanceNameToString);
434
435} // namespace
Xiang Wangdd0edc62023-02-08 16:47:06 -0800436} // namespace aidl::android::hardware::thermal
Peiyong Lin56960752022-09-30 21:52:52 +0000437
438int main(int argc, char** argv) {
439 ::testing::InitGoogleTest(&argc, argv);
440 ABinderProcess_setThreadPoolMaxThreadCount(1);
441 ABinderProcess_startThreadPool();
442 return RUN_ALL_TESTS();
443}