blob: ecb64a706eef7a8bc300f87131e3479eafbb9ee8 [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
28#include <aidl/Gtest.h>
29#include <aidl/Vintf.h>
30#include <aidl/android/hardware/thermal/BnThermal.h>
31#include <aidl/android/hardware/thermal/BnThermalChangedCallback.h>
32#include <android-base/logging.h>
33#include <android-base/properties.h>
34#include <android/binder_ibinder.h>
35#include <android/binder_interface_utils.h>
36#include <android/binder_manager.h>
37#include <android/binder_process.h>
38#include <android/binder_status.h>
39#include <gtest/gtest.h>
40
41#include <unistd.h>
42
43namespace aidl::android::hardware::thermal {
44
45namespace {
46
47using ::android::sp;
48using android::hardware::thermal::CoolingDevice;
49using android::hardware::thermal::IThermal;
50using android::hardware::thermal::Temperature;
51using android::hardware::thermal::TemperatureType;
52
53using namespace std::string_literals;
54using namespace std::chrono_literals;
55
56static const Temperature kThrottleTemp = {
57 .type = TemperatureType::SKIN,
58 .name = "test temperature sensor",
59 .value = 98.6,
60 .throttlingStatus = ThrottlingSeverity::CRITICAL,
61};
62
63// Callback class for receiving thermal event notifications from main class
64class ThermalCallback : public BnThermalChangedCallback {
65 public:
66 ndk::ScopedAStatus notifyThrottling(const Temperature&) override {
67 {
68 std::lock_guard<std::mutex> lock(mMutex);
69 mInvoke = true;
70 }
71 mNotifyThrottling.notify_all();
72 return ndk::ScopedAStatus::ok();
73 }
74
75 template <typename R, typename P>
76 [[nodiscard]] bool waitForCallback(std::chrono::duration<R, P> duration) {
77 std::unique_lock<std::mutex> lock(mMutex);
78 bool r = mNotifyThrottling.wait_for(lock, duration, [this] { return this->mInvoke; });
79 mInvoke = false;
80 return r;
81 }
82
83 private:
84 std::mutex mMutex;
85 std::condition_variable mNotifyThrottling;
86 bool mInvoke = false;
87};
88
89// The main test class for THERMAL HIDL HAL.
90class ThermalAidlTest : public testing::TestWithParam<std::string> {
91 public:
92 void SetUp() override {
93 AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
94 ASSERT_NE(binder, nullptr);
95 mThermal = IThermal::fromBinder(ndk::SpAIBinder(binder));
96
97 mThermalCallback = ndk::SharedRefBase::make<ThermalCallback>();
98 ASSERT_NE(mThermalCallback, nullptr);
Xiang Wange7b177e2022-12-21 17:55:11 -080099 ::ndk::ScopedAStatus status = mThermal->registerThermalChangedCallback(mThermalCallback);
100 ASSERT_TRUE(status.isOk()) << status.getMessage();
Peiyong Lin56960752022-09-30 21:52:52 +0000101 }
102
103 void TearDown() override {
Xiang Wange7b177e2022-12-21 17:55:11 -0800104 ::ndk::ScopedAStatus status = mThermal->unregisterThermalChangedCallback(mThermalCallback);
105 ASSERT_TRUE(status.isOk()) << status.getMessage();
Peiyong Lin56960752022-09-30 21:52:52 +0000106 // Expect to fail if unregister again
Xiang Wangd43e8732023-02-07 12:10:33 -0800107 status = mThermal->unregisterThermalChangedCallback(mThermalCallback);
Xiang Wangd43e8732023-02-07 12:10:33 -0800108 ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
Peiyong Lin56960752022-09-30 21:52:52 +0000109 }
110
111 protected:
112 std::shared_ptr<IThermal> mThermal;
113 std::shared_ptr<ThermalCallback> mThermalCallback;
114};
115
116// Test ThermalChangedCallback::notifyThrottling().
117// This just calls into and back from our local ThermalChangedCallback impl.
118TEST_P(ThermalAidlTest, NotifyThrottlingTest) {
119 std::shared_ptr<ThermalCallback> thermalCallback = ndk::SharedRefBase::make<ThermalCallback>();
Xiang Wange7b177e2022-12-21 17:55:11 -0800120 ::ndk::ScopedAStatus status = thermalCallback->notifyThrottling(kThrottleTemp);
121 ASSERT_TRUE(status.isOk()) << status.getMessage();
Peiyong Lin56960752022-09-30 21:52:52 +0000122 ASSERT_TRUE(thermalCallback->waitForCallback(200ms));
123}
124
Xiang Wange7b177e2022-12-21 17:55:11 -0800125// Test Thermal->registerThermalChangedCallback.
126TEST_P(ThermalAidlTest, RegisterThermalChangedCallbackTest) {
127 // Expect to fail with same callback
128 ::ndk::ScopedAStatus status = mThermal->registerThermalChangedCallback(mThermalCallback);
129 ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
130 // Expect to fail with null callback
131 status = mThermal->registerThermalChangedCallback(nullptr);
Sean Dooher3869fa62023-06-12 20:14:00 +0000132 ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT
133 || status.getExceptionCode() == EX_NULL_POINTER);
Xiang Wange7b177e2022-12-21 17:55:11 -0800134 std::shared_ptr<ThermalCallback> localThermalCallback =
135 ndk::SharedRefBase::make<ThermalCallback>();
136 // Expect to succeed with different callback
137 status = mThermal->registerThermalChangedCallback(localThermalCallback);
138 ASSERT_TRUE(status.isOk()) << status.getMessage();
Xiang Wange7b177e2022-12-21 17:55:11 -0800139 // Remove the local callback
140 status = mThermal->unregisterThermalChangedCallback(localThermalCallback);
141 ASSERT_TRUE(status.isOk()) << status.getMessage();
142 // Expect to fail with null callback
143 status = mThermal->unregisterThermalChangedCallback(nullptr);
Sean Dooher3869fa62023-06-12 20:14:00 +0000144 ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT
145 || status.getExceptionCode() == EX_NULL_POINTER);
Xiang Wange7b177e2022-12-21 17:55:11 -0800146}
147
148// Test Thermal->registerThermalChangedCallbackWithType.
149TEST_P(ThermalAidlTest, RegisterThermalChangedCallbackWithTypeTest) {
150 // Expect to fail with same callback
151 ::ndk::ScopedAStatus status = mThermal->registerThermalChangedCallbackWithType(
152 mThermalCallback, TemperatureType::SKIN);
153 ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
154 // Expect to fail with null callback
155 status = mThermal->registerThermalChangedCallbackWithType(nullptr, TemperatureType::SKIN);
Sean Dooher3869fa62023-06-12 20:14:00 +0000156 ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT
157 || status.getExceptionCode() == EX_NULL_POINTER);
Xiang Wange7b177e2022-12-21 17:55:11 -0800158 std::shared_ptr<ThermalCallback> localThermalCallback =
159 ndk::SharedRefBase::make<ThermalCallback>();
160 // Expect to succeed with different callback
161 status = mThermal->registerThermalChangedCallbackWithType(localThermalCallback,
162 TemperatureType::SKIN);
163 ASSERT_TRUE(status.isOk()) << status.getMessage();
Xiang Wange7b177e2022-12-21 17:55:11 -0800164 // Remove the local callback
165 status = mThermal->unregisterThermalChangedCallback(localThermalCallback);
166 ASSERT_TRUE(status.isOk()) << status.getMessage();
167 // Expect to fail with null callback
168 status = mThermal->unregisterThermalChangedCallback(nullptr);
Sean Dooher3869fa62023-06-12 20:14:00 +0000169 ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT
170 || status.getExceptionCode() == EX_NULL_POINTER);
Xiang Wange7b177e2022-12-21 17:55:11 -0800171}
172
173// Test Thermal->getCurrentTemperatures().
174TEST_P(ThermalAidlTest, TemperatureTest) {
175 std::vector<Temperature> ret;
176 ::ndk::ScopedAStatus status = mThermal->getTemperatures(&ret);
177 if (status.isOk()) {
178 for (auto& i : ret) {
179 EXPECT_LT(0u, i.name.size());
180 LOG(INFO) << i.name + " " + toString(i.type) << "\n";
181 }
182 } else {
183 ASSERT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode());
184 }
185
186 auto types = ::ndk::enum_range<TemperatureType>();
187 for (const auto& type : types) {
188 status = mThermal->getTemperaturesWithType(type, &ret);
189
190 if (status.isOk()) {
191 for (auto& i : ret) {
192 EXPECT_EQ(type, i.type) << "Expect type " + toString(type) + " but got " +
193 toString(i.type) + " for " + i.name;
194 EXPECT_LT(0u, i.name.size());
195 }
196 } else {
197 ASSERT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode());
198 }
199 }
200}
201
202// Test Thermal->getTemperatureThresholds().
203TEST_P(ThermalAidlTest, TemperatureThresholdTest) {
204 std::vector<TemperatureThreshold> ret;
205 ::ndk::ScopedAStatus status = mThermal->getTemperatureThresholds(&ret);
206 if (status.isOk()) {
207 for (auto& i : ret) {
208 EXPECT_LT(0u, i.name.size());
209 LOG(INFO) << i.name + " " + toString(i.type) << "\n";
210 }
211 } else {
212 ASSERT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode());
213 }
214
215 auto types = ::ndk::enum_range<TemperatureType>();
216 for (const auto& type : types) {
217 status = mThermal->getTemperatureThresholdsWithType(type, &ret);
218
219 if (status.isOk()) {
220 for (auto& i : ret) {
221 EXPECT_EQ(type, i.type) << "Expect type " + toString(type) + " but got " +
222 toString(i.type) + " for " + i.name;
223 EXPECT_LT(0u, i.name.size());
224 }
225 } else {
226 ASSERT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode());
227 }
228 }
229}
230
Xiang Wange88a10c2023-09-12 17:29:38 -0700231// Test Thermal->getTemperatureThresholdsWithType(SKIN).
232// @VsrTest = GMS-VSR-3.2.5-001
233// @VsrTest = VSR-3.2.5-001
234// @VsrTest = GMS-VSR-3.2.5-002
235// @VsrTest = VSR-3.2.5-002
236TEST_P(ThermalAidlTest, SkinTemperatureThresholdsTest) {
237 auto apiLevel = ::android::base::GetIntProperty<int32_t>("ro.vendor.api_level", 0);
238 if (apiLevel < 35) {
239 GTEST_SKIP() << "Skipping test as the vendor level is below 35: " << apiLevel;
240 }
241 std::vector<Temperature> temperatures;
242 ::ndk::ScopedAStatus status =
243 mThermal->getTemperaturesWithType(TemperatureType::SKIN, &temperatures);
244 ASSERT_TRUE(status.isOk()) << "getTemperaturesWithType(SKIN) failed";
245 ASSERT_FALSE(temperatures.empty()) << "getTemperaturesWithType(SKIN) returns empty";
246 ASSERT_EQ(1, temperatures.size())
247 << "getTemperaturesWithType(SKIN) returns multiple temperatures";
248
249 std::vector<TemperatureThreshold> thresholds;
250 status = mThermal->getTemperatureThresholdsWithType(TemperatureType::SKIN, &thresholds);
251 ASSERT_TRUE(status.isOk()) << "getTemperatureThresholdsWithType(SKIN) failed";
252 ASSERT_FALSE(thresholds.empty()) << "getTemperatureThresholdsWithType(SKIN) returns empty";
253 ASSERT_EQ(1, thresholds.size())
254 << "getTemperatureThresholdsWithType(SKIN) returns multiple thresholds";
255 auto temperature = temperatures[0];
256 auto threshold = thresholds[0];
257 ASSERT_EQ(temperature.name, threshold.name);
258 auto severities = ::ndk::enum_range<ThrottlingSeverity>();
259 auto cardinality = std::distance(severities.begin(), severities.end());
260 ASSERT_NE(NAN, temperature.value);
261 ASSERT_EQ(cardinality, threshold.hotThrottlingThresholds.size());
262 float lastThreshold = threshold.hotThrottlingThresholds[1];
263 // skip NONE, and check that the rest should be set and non-decreasing
264 for (auto i = 2; i < cardinality; i++) {
265 float t = threshold.hotThrottlingThresholds[i];
266 ASSERT_NE(NAN, t);
267 ASSERT_TRUE(t >= lastThreshold) << "Temperature thresholds should be non-decreasing "
268 << "but got " << t << " for status " << i << " and "
269 << lastThreshold << " for status " << i - 1;
270 lastThreshold = t;
271 }
272}
273
Xiang Wange7b177e2022-12-21 17:55:11 -0800274// Test Thermal->getCoolingDevices().
275TEST_P(ThermalAidlTest, CoolingDeviceTest) {
276 std::vector<CoolingDevice> ret;
277 ::ndk::ScopedAStatus status = mThermal->getCoolingDevices(&ret);
278 if (status.isOk()) {
279 for (auto& i : ret) {
280 EXPECT_LT(0u, i.name.size());
281 LOG(INFO) << i.name + " " + toString(i.type) << "\n";
282 }
283 } else {
284 ASSERT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode());
285 }
286
287 auto types = ::ndk::enum_range<CoolingType>();
288 for (const auto& type : types) {
289 status = mThermal->getCoolingDevicesWithType(type, &ret);
290 if (status.isOk()) {
291 ASSERT_TRUE(status.isOk());
292 for (auto& i : ret) {
293 EXPECT_EQ(type, i.type) << "Expect type " + toString(type) + " but got " +
294 toString(i.type) + " for " + i.name;
295 EXPECT_LT(0u, i.name.size());
296 }
297 } else {
298 ASSERT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode());
299 }
300 }
301}
302
Peiyong Lin56960752022-09-30 21:52:52 +0000303GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ThermalAidlTest);
304INSTANTIATE_TEST_SUITE_P(
305 Thermal, ThermalAidlTest,
306 testing::ValuesIn(::android::getAidlHalInstanceNames(IThermal::descriptor)),
307 ::android::PrintInstanceNameToString);
308
309} // namespace
Xiang Wangdd0edc62023-02-08 16:47:06 -0800310} // namespace aidl::android::hardware::thermal
Peiyong Lin56960752022-09-30 21:52:52 +0000311
312int main(int argc, char** argv) {
313 ::testing::InitGoogleTest(&argc, argv);
314 ABinderProcess_setThreadPoolMaxThreadCount(1);
315 ABinderProcess_startThreadPool();
316 return RUN_ALL_TESTS();
317}