Move thermal utils to hardware/interfaces
Bug: b/269370789
Test: m
Change-Id: I67d035271c177dfee88ac7272baa7cc9cdef3e00
Merged-In: I67d035271c177dfee88ac7272baa7cc9cdef3e00
diff --git a/thermal/utils/Android.bp b/thermal/utils/Android.bp
new file mode 100644
index 0000000..72e1e34
--- /dev/null
+++ b/thermal/utils/Android.bp
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_static {
+ name: "libthermalutils",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+ srcs: [
+ "ThermalHidlWrapper.cpp",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ shared_libs: [
+ "android.hardware.thermal@2.0",
+ "android.hardware.thermal-V1-ndk",
+ ],
+}
diff --git a/thermal/utils/ThermalHidlWrapper.cpp b/thermal/utils/ThermalHidlWrapper.cpp
new file mode 100644
index 0000000..05a992a
--- /dev/null
+++ b/thermal/utils/ThermalHidlWrapper.cpp
@@ -0,0 +1,305 @@
+/*
+ * 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.
+ */
+
+#include "include/thermalutils/ThermalHidlWrapper.h"
+
+#include <hidl/HidlTransportSupport.h>
+
+#include <cmath>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace thermal {
+
+using ::android::hardware::Void;
+
+namespace {
+
+template <typename T, typename U>
+Return<void> setFailureAndCallback(T _hidl_cb, hidl_vec<U> data, std::string_view debug_msg) {
+ ThermalStatus status;
+ status.code = ThermalStatusCode::FAILURE;
+ status.debugMessage = debug_msg.data();
+ _hidl_cb(status, data);
+ return Void();
+}
+
+template <typename T>
+Return<void> setFailureAndCallback(T _hidl_cb, std::string_view debug_msg) {
+ ThermalStatus status;
+ status.code = ThermalStatusCode::FAILURE;
+ status.debugMessage = debug_msg.data();
+ _hidl_cb(status);
+ return Void();
+}
+
+template <typename T, typename U>
+Return<void> setInitFailureAndCallback(T _hidl_cb, hidl_vec<U> data) {
+ return setFailureAndCallback(
+ _hidl_cb, data, "Thermal AIDL HAL client used by HIDL wrapper was not initialized");
+}
+
+template <typename T>
+Return<void> setInitFailureAndCallback(T _hidl_cb) {
+ return setFailureAndCallback(
+ _hidl_cb, "Thermal AIDL HAL client used by HIDL wrapper was not initialized");
+}
+
+template <typename T, typename U>
+Return<void> setUnsupportedFailureAndCallback(T _hidl_cb, hidl_vec<U> data) {
+ return setFailureAndCallback(_hidl_cb, data, "Operation unsupported by Thermal HIDL wrapper");
+}
+
+TemperatureType_2_0 convertAidlTemperatureType(const TemperatureType& type) {
+ if (type < TemperatureType::CPU || type > TemperatureType::NPU) {
+ return TemperatureType_2_0::UNKNOWN;
+ }
+ return static_cast<TemperatureType_2_0>(type);
+}
+
+CoolingType_2_0 convertAidlCoolingType(const CoolingType& type) {
+ if (type < CoolingType::FAN || type > CoolingType::COMPONENT) {
+ return CoolingType_2_0::COMPONENT;
+ }
+ return static_cast<CoolingType_2_0>(type);
+}
+
+Temperature_2_0 convertAidlTemperature(const Temperature& temperature) {
+ Temperature_2_0 t = Temperature_2_0{
+ convertAidlTemperatureType(temperature.type), temperature.name, temperature.value,
+ static_cast<ThrottlingSeverity_2_0>(temperature.throttlingStatus)};
+ return t;
+}
+
+CoolingDevice_2_0 convertAidlCoolingDevice(const CoolingDevice& cooling_device) {
+ CoolingDevice_2_0 t =
+ CoolingDevice_2_0{convertAidlCoolingType(cooling_device.type), cooling_device.name,
+ static_cast<uint64_t>(cooling_device.value)};
+ return t;
+}
+TemperatureThreshold_2_0 convertAidlTemperatureThreshold(const TemperatureThreshold& threshold) {
+ TemperatureThreshold_2_0 t =
+ TemperatureThreshold_2_0{convertAidlTemperatureType(threshold.type), threshold.name,
+ threshold.hotThrottlingThresholds.data(),
+ threshold.coldThrottlingThresholds.data(), NAN};
+ return t;
+}
+
+} // namespace
+
+// Methods from ::android::hardware::thermal::V1_0::IThermal follow.
+Return<void> ThermalHidlWrapper::getTemperatures(getTemperatures_cb _hidl_cb) {
+ hidl_vec<Temperature_1_0> ret_1_0;
+ setUnsupportedFailureAndCallback(_hidl_cb, ret_1_0);
+ return Void();
+}
+
+Return<void> ThermalHidlWrapper::getCpuUsages(
+ std::function<void(const ThermalStatus&, const hidl_vec<CpuUsage>&)> _hidl_cb) {
+ hidl_vec<CpuUsage> ret_1_0;
+ setUnsupportedFailureAndCallback(_hidl_cb, ret_1_0);
+ return Void();
+}
+
+Return<void> ThermalHidlWrapper::getCoolingDevices(
+ std::function<void(const ThermalStatus&, const hidl_vec<CoolingDevice_1_0>&)> _hidl_cb) {
+ hidl_vec<CoolingDevice_1_0> ret_1_0;
+ setUnsupportedFailureAndCallback(_hidl_cb, ret_1_0);
+ return Void();
+}
+
+// Methods from ::android::hardware::thermal::V2_0::IThermal follow.
+Return<void> ThermalHidlWrapper::getCurrentTemperatures(
+ bool filterType, TemperatureType_2_0 type,
+ std::function<void(const ThermalStatus&, const hidl_vec<Temperature_2_0>&)> _hidl_cb) {
+ hidl_vec<Temperature_2_0> ret_2_0;
+ if (!thermal_service_) {
+ setInitFailureAndCallback(_hidl_cb, ret_2_0);
+ }
+
+ std::vector<Temperature> ret_aidl;
+ ThermalStatus status;
+ ::ndk::ScopedAStatus a_status;
+ if (filterType) {
+ a_status = thermal_service_->getTemperaturesWithType(static_cast<TemperatureType>(type),
+ &ret_aidl);
+ } else {
+ a_status = thermal_service_->getTemperatures(&ret_aidl);
+ }
+ if (a_status.isOk()) {
+ std::vector<Temperature_2_0> ret;
+ for (const auto& temperature : ret_aidl) {
+ ret.push_back(convertAidlTemperature(temperature));
+ }
+ _hidl_cb(status, hidl_vec<Temperature_2_0>(ret));
+ } else {
+ setFailureAndCallback(_hidl_cb, ret_2_0, a_status.getMessage());
+ }
+ return Void();
+}
+
+Return<void> ThermalHidlWrapper::getTemperatureThresholds(
+ bool filterType, TemperatureType_2_0 type,
+ std::function<void(const ThermalStatus&, const hidl_vec<TemperatureThreshold_2_0>&)>
+ _hidl_cb) {
+ hidl_vec<TemperatureThreshold_2_0> ret_2_0;
+ if (!thermal_service_) {
+ setInitFailureAndCallback(_hidl_cb, ret_2_0);
+ }
+
+ std::vector<TemperatureThreshold> ret_aidl;
+ ThermalStatus status;
+ ::ndk::ScopedAStatus a_status;
+ if (filterType) {
+ a_status = thermal_service_->getTemperatureThresholdsWithType(
+ static_cast<TemperatureType>(type), &ret_aidl);
+ } else {
+ a_status = thermal_service_->getTemperatureThresholds(&ret_aidl);
+ }
+ if (a_status.isOk()) {
+ std::vector<TemperatureThreshold_2_0> ret;
+ for (const auto& threshold : ret_aidl) {
+ ret.push_back(convertAidlTemperatureThreshold(threshold));
+ }
+ _hidl_cb(status, hidl_vec<TemperatureThreshold_2_0>(ret));
+ } else {
+ setFailureAndCallback(_hidl_cb, ret_2_0, a_status.getMessage());
+ }
+ return Void();
+}
+
+Return<void> ThermalHidlWrapper::registerThermalChangedCallback(
+ const sp<IThermalChangedCallback_2_0>& callback, bool filterType, TemperatureType_2_0 type,
+ std::function<void(const ThermalStatus&)> _hidl_cb) {
+ if (!thermal_service_) {
+ setInitFailureAndCallback(_hidl_cb);
+ }
+ if (callback == nullptr) {
+ setFailureAndCallback(_hidl_cb, "Invalid nullptr callback");
+ return Void();
+ }
+ std::lock_guard<std::mutex> _lock(callback_wrappers_mutex_);
+ for (const auto& callback_wrapper : callback_wrappers_) {
+ if (::android::hardware::interfacesEqual(callback_wrapper->callback_2_0_.get(),
+ callback.get())) {
+ setFailureAndCallback(_hidl_cb, "The callback was already registered through wrapper");
+ return Void();
+ }
+ }
+ std::shared_ptr<IThermalChangedCallbackWrapper> callback_wrapper =
+ ndk::SharedRefBase::make<IThermalChangedCallbackWrapper>(callback);
+ ::ndk::ScopedAStatus a_status;
+ ThermalStatus status;
+ if (filterType) {
+ a_status = thermal_service_->registerThermalChangedCallbackWithType(
+ callback_wrapper, static_cast<TemperatureType>(type));
+ } else {
+ a_status = thermal_service_->registerThermalChangedCallback(callback_wrapper);
+ }
+ if (a_status.isOk()) {
+ callback_wrappers_.push_back(callback_wrapper);
+ _hidl_cb(status);
+ } else {
+ setFailureAndCallback(_hidl_cb, a_status.getMessage());
+ }
+ return Void();
+}
+
+Return<void> ThermalHidlWrapper::unregisterThermalChangedCallback(
+ const sp<IThermalChangedCallback_2_0>& callback,
+ std::function<void(const ThermalStatus&)> _hidl_cb) {
+ if (!thermal_service_) {
+ setInitFailureAndCallback(_hidl_cb);
+ }
+ if (callback == nullptr) {
+ setFailureAndCallback(_hidl_cb, "Invalid nullptr callback");
+ return Void();
+ }
+ std::lock_guard<std::mutex> _lock(callback_wrappers_mutex_);
+ for (auto it = callback_wrappers_.begin(); it != callback_wrappers_.end(); it++) {
+ auto callback_wrapper = *it;
+ if (::android::hardware::interfacesEqual(callback_wrapper->callback_2_0_.get(),
+ callback.get())) {
+ ::ndk::ScopedAStatus a_status;
+ ThermalStatus status;
+ a_status = thermal_service_->unregisterThermalChangedCallback(callback_wrapper);
+ if (a_status.isOk()) {
+ callback_wrappers_.erase(it);
+ _hidl_cb(status);
+ } else {
+ setFailureAndCallback(_hidl_cb, a_status.getMessage());
+ }
+ return Void();
+ }
+ }
+ setFailureAndCallback(_hidl_cb, "The callback was not registered through wrapper before");
+ return Void();
+}
+
+Return<void> ThermalHidlWrapper::getCurrentCoolingDevices(
+ bool filterType, CoolingType_2_0 type,
+ std::function<void(const ThermalStatus&, const hidl_vec<CoolingDevice_2_0>&)> _hidl_cb) {
+ hidl_vec<CoolingDevice_2_0> ret_2_0;
+ if (!thermal_service_) {
+ setInitFailureAndCallback(_hidl_cb, ret_2_0);
+ }
+
+ std::vector<CoolingDevice> ret_aidl;
+ ThermalStatus status;
+ ::ndk::ScopedAStatus a_status;
+ if (filterType) {
+ a_status = thermal_service_->getCoolingDevicesWithType(static_cast<CoolingType>(type),
+ &ret_aidl);
+ } else {
+ a_status = thermal_service_->getCoolingDevices(&ret_aidl);
+ }
+ if (a_status.isOk()) {
+ std::vector<CoolingDevice_2_0> ret;
+ for (const auto& cooling_device : ret_aidl) {
+ ret.push_back(convertAidlCoolingDevice(cooling_device));
+ }
+ _hidl_cb(status, hidl_vec<CoolingDevice_2_0>(ret));
+ } else {
+ setFailureAndCallback(_hidl_cb, ret_2_0, a_status.getMessage());
+ }
+ return Void();
+}
+
+// Methods from ::android::hidl::base::V1_0::IBase follow.
+Return<void> ThermalHidlWrapper::debug(const hidl_handle& handle,
+ const hidl_vec<hidl_string>& args) {
+ if (handle != nullptr && handle->numFds >= 1) {
+ int fd = handle->data[0];
+ char** arr = new char*[args.size()];
+ for (size_t i = 0; i < args.size(); i++) {
+ arr[i] = strdup(args[i].c_str());
+ }
+ thermal_service_->dump(fd, (const char**)arr, args.size());
+ }
+ return Void();
+}
+
+::ndk::ScopedAStatus ThermalHidlWrapper::IThermalChangedCallbackWrapper::notifyThrottling(
+ const Temperature& temperature) {
+ callback_2_0_->notifyThrottling(convertAidlTemperature(temperature));
+ return ::ndk::ScopedAStatus::ok();
+}
+
+} // namespace thermal
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/thermal/utils/include/thermalutils/ThermalHidlWrapper.h b/thermal/utils/include/thermalutils/ThermalHidlWrapper.h
new file mode 100644
index 0000000..1fec100
--- /dev/null
+++ b/thermal/utils/include/thermalutils/ThermalHidlWrapper.h
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+#include <aidl/android/hardware/thermal/BnThermalChangedCallback.h>
+#include <aidl/android/hardware/thermal/IThermal.h>
+#include <android/hardware/thermal/2.0/IThermal.h>
+#include <android/hardware/thermal/2.0/IThermalChangedCallback.h>
+#include <android/hardware/thermal/2.0/types.h>
+#include <hidl/Status.h>
+
+#include <utility>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace thermal {
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+
+using IThermal_Aidl = ::aidl::android::hardware::thermal::IThermal;
+using ::android::hardware::thermal::V1_0::CpuUsage;
+using CoolingType_2_0 = ::android::hardware::thermal::V2_0::CoolingType;
+using CoolingDevice_1_0 = ::android::hardware::thermal::V1_0::CoolingDevice;
+using CoolingDevice_2_0 = ::android::hardware::thermal::V2_0::CoolingDevice;
+using IThermal_2_0 = ::android::hardware::thermal::V2_0::IThermal;
+using IThermalChangedCallback_2_0 = ::android::hardware::thermal::V2_0::IThermalChangedCallback;
+using Temperature_1_0 = ::android::hardware::thermal::V1_0::Temperature;
+using Temperature_2_0 = ::android::hardware::thermal::V2_0::Temperature;
+using TemperatureType_2_0 = ::android::hardware::thermal::V2_0::TemperatureType;
+
+using ::android::hardware::thermal::V1_0::ThermalStatus;
+using ::android::hardware::thermal::V1_0::ThermalStatusCode;
+
+using TemperatureThreshold_2_0 = ::android::hardware::thermal::V2_0::TemperatureThreshold;
+using ThrottlingSeverity_2_0 = ::android::hardware::thermal::V2_0::ThrottlingSeverity;
+
+// This wrapper converts all Thermal HIDL 2.0 calls to AIDL calls and converts AIDL response to
+// HIDL 2.0 response.
+//
+// For Thermal HIDL 1.0 calls, it returns unsupported error.
+class ThermalHidlWrapper : public IThermal_2_0 {
+ public:
+ explicit ThermalHidlWrapper(::std::shared_ptr<IThermal_Aidl> thermal_service)
+ : thermal_service_(std::move(thermal_service)) {}
+
+ // Methods from ::android::hardware::thermal::V1_0::IThermal follow.
+ Return<void> getTemperatures(getTemperatures_cb _hidl_cb) override;
+ Return<void> getCpuUsages(getCpuUsages_cb _hidl_cb) override;
+ Return<void> getCoolingDevices(getCoolingDevices_cb _hidl_cb) override;
+
+ // Methods from ::android::hardware::thermal::V2_0::IThermal follow.
+ Return<void> getCurrentTemperatures(bool filterType, TemperatureType_2_0 type,
+ getCurrentTemperatures_cb _hidl_cb) override;
+ Return<void> getTemperatureThresholds(bool filterType, TemperatureType_2_0 type,
+ getTemperatureThresholds_cb _hidl_cb) override;
+ Return<void> registerThermalChangedCallback(
+ const sp<IThermalChangedCallback_2_0>& callback, bool filterType,
+ TemperatureType_2_0 type, registerThermalChangedCallback_cb _hidl_cb) override;
+ Return<void> unregisterThermalChangedCallback(
+ const sp<IThermalChangedCallback_2_0>& callback,
+ unregisterThermalChangedCallback_cb _hidl_cb) override;
+ Return<void> getCurrentCoolingDevices(bool filterType, CoolingType_2_0 type,
+ getCurrentCoolingDevices_cb _hidl_cb) override;
+
+ // Methods from ::android::hidl::base::V1_0::IBase follow.
+ Return<void> debug(const hidl_handle& handle, const hidl_vec<hidl_string>& args) override;
+
+ private:
+ class IThermalChangedCallbackWrapper : public BnThermalChangedCallback {
+ public:
+ explicit IThermalChangedCallbackWrapper(const sp<IThermalChangedCallback_2_0>& callback_2_0)
+ : callback_2_0_(callback_2_0) {}
+ ::ndk::ScopedAStatus notifyThrottling(const Temperature& temperature) override;
+ sp<IThermalChangedCallback_2_0> callback_2_0_;
+ };
+
+ // Reference to thermal service.
+ ::std::shared_ptr<IThermal_Aidl> thermal_service_;
+ // Mutex lock for read/write on callback wrappers.
+ std::mutex callback_wrappers_mutex_;
+ // All thermal changed callback wrappers registered.
+ ::std::vector<std::shared_ptr<IThermalChangedCallbackWrapper>> callback_wrappers_;
+};
+
+} // namespace thermal
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/thermal/utils/tests/Android.bp b/thermal/utils/tests/Android.bp
new file mode 100644
index 0000000..fd74e8b
--- /dev/null
+++ b/thermal/utils/tests/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+ name: "ThermalHidlWrapperTest",
+ srcs: ["ThermalHidlWrapperTest.cpp"],
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "android.hardware.thermal@1.0",
+ "android.hardware.thermal@2.0",
+ "android.hardware.thermal-V1-ndk",
+ ],
+ static_libs: [
+ "libthermalutils",
+ "libgtest",
+ ],
+ test_suites: [
+ "device-tests",
+ ],
+}
diff --git a/thermal/utils/tests/ThermalHidlWrapperTest.cpp b/thermal/utils/tests/ThermalHidlWrapperTest.cpp
new file mode 100644
index 0000000..1723a1a
--- /dev/null
+++ b/thermal/utils/tests/ThermalHidlWrapperTest.cpp
@@ -0,0 +1,302 @@
+/*
+ * 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 "thermal_hidl_wrapper_test"
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/thermal/BnThermal.h>
+#include <aidl/android/hardware/thermal/BnThermalChangedCallback.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android/binder_status.h>
+#include <android/hardware/thermal/2.0/IThermal.h>
+#include <android/hardware/thermal/2.0/IThermalChangedCallback.h>
+#include <android/hardware/thermal/2.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <thermalutils/ThermalHidlWrapper.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <chrono>
+#include <cmath>
+#include <memory>
+#include <string>
+#include <thread>
+#include <vector>
+
+namespace aidl::android::hardware::thermal {
+
+namespace {
+
+using ::android::sp;
+using ::android::hardware::hidl_enum_range;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using ::android::hardware::thermal::V1_0::ThermalStatus;
+using ::android::hardware::thermal::V1_0::ThermalStatusCode;
+using ::android::hardware::thermal::V2_0::CoolingDevice;
+using ::android::hardware::thermal::V2_0::CoolingType;
+using IThermal_2_0 = ::android::hardware::thermal::V2_0::IThermal;
+using ::android::hardware::thermal::V2_0::IThermalChangedCallback;
+using ::android::hardware::thermal::V2_0::Temperature;
+using ::android::hardware::thermal::V2_0::TemperatureThreshold;
+using ::android::hardware::thermal::V2_0::TemperatureType;
+using ::android::hardware::thermal::V2_0::ThrottlingSeverity;
+
+constexpr char kCallbackNameNotifyThrottling[] = "notifyThrottling";
+static const Temperature kThrottleTemp = {
+ .type = TemperatureType::SKIN,
+ .name = "test temperature sensor",
+ .value = 98.6,
+ .throttlingStatus = ThrottlingSeverity::CRITICAL,
+};
+
+class ThermalCallbackArgs {
+ public:
+ Temperature temperature;
+};
+
+// Callback class for receiving thermal event notifications from main class
+class ThermalCallback : public ::testing::VtsHalHidlTargetCallbackBase<ThermalCallbackArgs>,
+ public IThermalChangedCallback {
+ public:
+ Return<void> notifyThrottling(const Temperature& temperature) override {
+ ThermalCallbackArgs args;
+ args.temperature = temperature;
+ NotifyFromCallback(kCallbackNameNotifyThrottling, args);
+ return Void();
+ }
+};
+
+// The main test class for THERMAL HIDL HAL 2.0.
+class ThermalHidlWrapperTest : public ::testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
+ ASSERT_NE(binder, nullptr);
+ mThermal = sp<ThermalHidlWrapper>::make(IThermal::fromBinder(ndk::SpAIBinder(binder)));
+ ASSERT_NE(mThermal, nullptr);
+ mThermalCallback = new (std::nothrow) ThermalCallback();
+ ASSERT_NE(mThermalCallback, nullptr);
+ auto ret = mThermal->registerThermalChangedCallback(
+ mThermalCallback, false, TemperatureType::SKIN,
+ [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ // Expect to fail if register again
+ ret = mThermal->registerThermalChangedCallback(
+ mThermalCallback, false, TemperatureType::SKIN,
+ [](ThermalStatus status) { EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ }
+
+ void TearDown() override {
+ auto ret = mThermal->unregisterThermalChangedCallback(
+ mThermalCallback,
+ [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ // Expect to fail if unregister again
+ ret = mThermal->unregisterThermalChangedCallback(
+ mThermalCallback,
+ [](ThermalStatus status) { EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ }
+
+ protected:
+ sp<IThermal_2_0> mThermal;
+ sp<ThermalCallback> mThermalCallback;
+}; // class ThermalHidlWrapperTest
+
+// Test ThermalChangedCallback::notifyThrottling().
+// This just calls into and back from our local ThermalChangedCallback impl.
+TEST_P(ThermalHidlWrapperTest, NotifyThrottlingTest) {
+ sp<ThermalCallback> thermalCallback = new (std::nothrow) ThermalCallback();
+ auto ret = thermalCallback->notifyThrottling(kThrottleTemp);
+ ASSERT_TRUE(ret.isOk());
+ auto res = thermalCallback->WaitForCallback(kCallbackNameNotifyThrottling);
+ EXPECT_TRUE(res.no_timeout);
+ ASSERT_TRUE(res.args);
+ EXPECT_EQ(kThrottleTemp, res.args->temperature);
+}
+
+// Test Thermal->registerThermalChangedCallback.
+TEST_P(ThermalHidlWrapperTest, RegisterThermalChangedCallbackTest) {
+ // Expect to fail with same callback
+ auto ret = mThermal->registerThermalChangedCallback(
+ mThermalCallback, false, TemperatureType::SKIN,
+ [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::FAILURE, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ // Expect to fail with null callback
+ ret = mThermal->registerThermalChangedCallback(
+ nullptr, false, TemperatureType::SKIN,
+ [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::FAILURE, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ sp<ThermalCallback> localThermalCallback = new (std::nothrow) ThermalCallback();
+ // Expect to succeed with different callback
+ ret = mThermal->registerThermalChangedCallback(
+ localThermalCallback, false, TemperatureType::SKIN,
+ [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ // Remove the local callback
+ ret = mThermal->unregisterThermalChangedCallback(
+ localThermalCallback,
+ [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ // Expect to fail with null callback
+ ret = mThermal->unregisterThermalChangedCallback(nullptr, [](ThermalStatus status) {
+ EXPECT_EQ(ThermalStatusCode::FAILURE, status.code);
+ });
+ ASSERT_TRUE(ret.isOk());
+}
+
+// Test Thermal->unregisterThermalChangedCallback.
+TEST_P(ThermalHidlWrapperTest, UnregisterThermalChangedCallbackTest) {
+ sp<ThermalCallback> localThermalCallback = new (std::nothrow) ThermalCallback();
+ // Expect to fail as the callback was not registered before
+ auto ret = mThermal->unregisterThermalChangedCallback(
+ localThermalCallback,
+ [](ThermalStatus status) { EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ // Register a local callback
+ ret = mThermal->registerThermalChangedCallback(
+ localThermalCallback, false, TemperatureType::SKIN,
+ [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ // Expect to succeed with callback removed
+ ret = mThermal->unregisterThermalChangedCallback(
+ localThermalCallback,
+ [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ // Expect to fail as the callback has been unregistered already
+ ret = mThermal->unregisterThermalChangedCallback(
+ localThermalCallback,
+ [](ThermalStatus status) { EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+}
+
+// Sanity test for Thermal::getCurrentTemperatures().
+TEST_P(ThermalHidlWrapperTest, TemperatureTest) {
+ mThermal->getCurrentTemperatures(false, TemperatureType::SKIN,
+ [](ThermalStatus status, hidl_vec<Temperature> temperatures) {
+ if (temperatures.size()) {
+ EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code);
+ } else {
+ EXPECT_NE(ThermalStatusCode::SUCCESS, status.code);
+ }
+ for (int i = 0; i < temperatures.size(); ++i) {
+ EXPECT_LT(0u, temperatures[i].name.size());
+ }
+ });
+ auto types = hidl_enum_range<TemperatureType>();
+ for (const auto& type : types) {
+ mThermal->getCurrentTemperatures(
+ true, type, [&type](ThermalStatus status, hidl_vec<Temperature> temperatures) {
+ if (temperatures.size()) {
+ EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code);
+ } else {
+ EXPECT_NE(ThermalStatusCode::SUCCESS, status.code);
+ }
+ for (int i = 0; i < temperatures.size(); ++i) {
+ EXPECT_EQ(type, temperatures[i].type);
+ EXPECT_LT(0u, temperatures[i].name.size());
+ }
+ });
+ }
+}
+
+// Sanity test for Thermal::getTemperatureThresholds().
+TEST_P(ThermalHidlWrapperTest, TemperatureThresholdTest) {
+ mThermal->getTemperatureThresholds(
+ false, TemperatureType::SKIN,
+ [](ThermalStatus status, hidl_vec<TemperatureThreshold> temperatures) {
+ if (temperatures.size()) {
+ EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code);
+ } else {
+ EXPECT_NE(ThermalStatusCode::SUCCESS, status.code);
+ }
+ });
+ for (int i = static_cast<int>(TemperatureType::UNKNOWN);
+ i <= static_cast<int>(TemperatureType::POWER_AMPLIFIER); ++i) {
+ auto type = static_cast<TemperatureType>(i);
+ mThermal->getTemperatureThresholds(
+ true, type,
+ [&type](ThermalStatus status, hidl_vec<TemperatureThreshold> temperatures) {
+ if (temperatures.size()) {
+ EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code);
+ } else {
+ EXPECT_NE(ThermalStatusCode::SUCCESS, status.code);
+ }
+ for (int i = 0; i < temperatures.size(); ++i) {
+ EXPECT_EQ(type, temperatures[i].type);
+ }
+ });
+ }
+}
+
+// Sanity test for Thermal::getCurrentCoolingDevices().
+TEST_P(ThermalHidlWrapperTest, CoolingDeviceTest) {
+ mThermal->getCurrentCoolingDevices(
+ false, CoolingType::CPU,
+ [](ThermalStatus status, hidl_vec<CoolingDevice> cooling_devices) {
+ if (cooling_devices.size()) {
+ EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code);
+ } else {
+ EXPECT_NE(ThermalStatusCode::SUCCESS, status.code);
+ }
+ for (int i = 0; i < cooling_devices.size(); ++i) {
+ EXPECT_LT(0u, cooling_devices[i].name.size());
+ }
+ });
+ for (int i = 0; i <= static_cast<int>(CoolingType::COMPONENT); ++i) {
+ auto type = static_cast<CoolingType>(i);
+ mThermal->getCurrentCoolingDevices(
+ true, type, [&type](ThermalStatus status, hidl_vec<CoolingDevice> cooling_devices) {
+ if (cooling_devices.size()) {
+ EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code);
+ } else {
+ EXPECT_NE(ThermalStatusCode::SUCCESS, status.code);
+ }
+ for (int i = 0; i < cooling_devices.size(); ++i) {
+ EXPECT_EQ(type, cooling_devices[i].type);
+ EXPECT_LT(0u, cooling_devices[i].name.size());
+ }
+ });
+ }
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ThermalHidlWrapperTest);
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, ThermalHidlWrapperTest,
+ testing::ValuesIn(::android::getAidlHalInstanceNames(IThermal::descriptor)),
+ ::android::hardware::PrintInstanceNameToString);
+
+} // namespace
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
+
+} // namespace aidl::android::hardware::thermal