thermal: support cooling device status change notification
1. support the powercap in CoolingDevice 2. support the notification when CoolingDevice status changed Bug: 312540064 Test: atest VtsHalThermalTargetTest Change-Id: I58e39c0a2c070317b574f1a5d4abfa582cc56f34
This commit is contained in:
parent
e91038dfc4
commit
2bbd1ec30c
9 changed files with 294 additions and 0 deletions
|
@ -38,4 +38,7 @@ parcelable CoolingDevice {
|
|||
android.hardware.thermal.CoolingType type;
|
||||
String name;
|
||||
long value;
|
||||
long powerLimitMw;
|
||||
long powerMw;
|
||||
long timeWindowMs;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
|
||||
// two cases:
|
||||
// 1). this is a frozen version file - do not edit this in any case.
|
||||
// 2). this is a 'current' file. If you make a backwards compatible change to
|
||||
// the interface (from the latest frozen version), the build system will
|
||||
// prompt you to update this file with `m <name>-update-api`.
|
||||
//
|
||||
// You must not make a backward incompatible change to any AIDL file built
|
||||
// with the aidl_interface module type with versions property set. The module
|
||||
// type is used to build AIDL files in a way that they can be used across
|
||||
// independently updatable components of the system. If a device is shipped
|
||||
// with such a backward incompatible change, it has a high risk of breaking
|
||||
// later when a module using the interface is updated, e.g., Mainline modules.
|
||||
|
||||
package android.hardware.thermal;
|
||||
/* @hide */
|
||||
@VintfStability
|
||||
interface ICoolingDeviceChangedCallback {
|
||||
oneway void notifyCoolingDeviceChanged(in android.hardware.thermal.CoolingDevice coolingDevice);
|
||||
}
|
|
@ -44,4 +44,6 @@ interface IThermal {
|
|||
void registerThermalChangedCallback(in android.hardware.thermal.IThermalChangedCallback callback);
|
||||
void registerThermalChangedCallbackWithType(in android.hardware.thermal.IThermalChangedCallback callback, in android.hardware.thermal.TemperatureType type);
|
||||
void unregisterThermalChangedCallback(in android.hardware.thermal.IThermalChangedCallback callback);
|
||||
void registerCoolingDeviceChangedCallbackWithType(in android.hardware.thermal.ICoolingDeviceChangedCallback callback, in android.hardware.thermal.CoolingType type);
|
||||
void unregisterCoolingDeviceChangedCallback(in android.hardware.thermal.ICoolingDeviceChangedCallback callback);
|
||||
}
|
||||
|
|
|
@ -40,4 +40,16 @@ parcelable CoolingDevice {
|
|||
* means deeper throttling.
|
||||
*/
|
||||
long value;
|
||||
/**
|
||||
* Power budget (mW) of the cooling device.
|
||||
*/
|
||||
long powerLimitMw;
|
||||
/**
|
||||
* Target cooling device's AVG power for the last time_window_ms.
|
||||
*/
|
||||
long powerMw;
|
||||
/**
|
||||
* The time window (millisecond) to calculate the power consumption
|
||||
*/
|
||||
long timeWindowMs;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 android.hardware.thermal;
|
||||
|
||||
import android.hardware.thermal.CoolingDevice;
|
||||
import android.hardware.thermal.Temperature;
|
||||
|
||||
/**
|
||||
* ICoolingDeviceChangedCallback send cooling device change notification to clients.
|
||||
* @hide
|
||||
*/
|
||||
@VintfStability
|
||||
interface ICoolingDeviceChangedCallback {
|
||||
/**
|
||||
* Send a cooling device change event to all ThermalHAL
|
||||
* cooling device event listeners.
|
||||
*
|
||||
* @param cooling_device The cooling device information associated with the
|
||||
* change event.
|
||||
*/
|
||||
oneway void notifyCoolingDeviceChanged(in CoolingDevice coolingDevice);
|
||||
}
|
|
@ -18,6 +18,7 @@ package android.hardware.thermal;
|
|||
|
||||
import android.hardware.thermal.CoolingDevice;
|
||||
import android.hardware.thermal.CoolingType;
|
||||
import android.hardware.thermal.ICoolingDeviceChangedCallback;
|
||||
import android.hardware.thermal.IThermalChangedCallback;
|
||||
import android.hardware.thermal.Temperature;
|
||||
import android.hardware.thermal.TemperatureThreshold;
|
||||
|
@ -188,4 +189,40 @@ interface IThermal {
|
|||
* getMessage() must be populated with human-readable error message.
|
||||
*/
|
||||
void unregisterThermalChangedCallback(in IThermalChangedCallback callback);
|
||||
|
||||
/**
|
||||
* Register an ICoolingDeviceChangedCallback for a given CoolingType, used by
|
||||
* the Thermal HAL to receive CDEV events when cooling device status
|
||||
* changed.
|
||||
* Multiple registrations with different ICoolingDeviceChangedCallback must be allowed.
|
||||
* Multiple registrations with same ICoolingDeviceChangedCallback is not allowed, client
|
||||
* should unregister the given ICoolingDeviceChangedCallback first.
|
||||
*
|
||||
* @param callback the ICoolingChangedCallback to use for receiving
|
||||
* cooling device events. If nullptr callback is given, the status code will be
|
||||
* STATUS_BAD_VALUE and the operation will fail.
|
||||
* @param type the type to be filtered.
|
||||
*
|
||||
* @throws EX_ILLEGAL_ARGUMENT If the callback is given nullptr or already registered. And the
|
||||
* getMessage() must be populated with human-readable error message.
|
||||
* @throws EX_ILLEGAL_STATE If the Thermal HAL is not initialized successfully. And the
|
||||
* getMessage() must be populated with human-readable error message.
|
||||
*/
|
||||
void registerCoolingDeviceChangedCallbackWithType(
|
||||
in ICoolingDeviceChangedCallback callback, in CoolingType type);
|
||||
|
||||
/**
|
||||
* Unregister an ICoolingDeviceChangedCallback, used by the Thermal HAL
|
||||
* to receive CDEV events when cooling device status changed.
|
||||
*
|
||||
* @param callback the ICoolingDeviceChangedCallback to use for receiving
|
||||
* cooling device events. if nullptr callback is given, the status code will be
|
||||
* STATUS_BAD_VALUE and the operation will fail.
|
||||
*
|
||||
* @throws EX_ILLEGAL_ARGUMENT If the callback is given nullptr or not previously registered.
|
||||
* And the getMessage() must be populated with human-readable error message.
|
||||
* @throws EX_ILLEGAL_STATE If the Thermal HAL is not initialized successfully. And the
|
||||
* getMessage() must be populated with human-readable error message.
|
||||
*/
|
||||
void unregisterCoolingDeviceChangedCallback(in ICoolingDeviceChangedCallback callback);
|
||||
}
|
||||
|
|
|
@ -142,4 +142,53 @@ ScopedAStatus Thermal::unregisterThermalChangedCallback(
|
|||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ScopedAStatus Thermal::registerCoolingDeviceChangedCallbackWithType(
|
||||
const std::shared_ptr<ICoolingDeviceChangedCallback>& in_callback, CoolingType in_type) {
|
||||
LOG(VERBOSE) << __func__ << " ICoolingDeviceChangedCallback: " << in_callback
|
||||
<< ", CoolingType: " << static_cast<int32_t>(in_type);
|
||||
if (in_callback == nullptr) {
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
|
||||
"Invalid nullptr callback");
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> _lock(cdev_callback_mutex_);
|
||||
if (std::any_of(cdev_callbacks_.begin(), cdev_callbacks_.end(),
|
||||
[&](const std::shared_ptr<ICoolingDeviceChangedCallback>& c) {
|
||||
return interfacesEqual(c, in_callback);
|
||||
})) {
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
|
||||
"Callback already registered");
|
||||
}
|
||||
cdev_callbacks_.push_back(in_callback);
|
||||
}
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ScopedAStatus Thermal::unregisterCoolingDeviceChangedCallback(
|
||||
const std::shared_ptr<ICoolingDeviceChangedCallback>& in_callback) {
|
||||
LOG(VERBOSE) << __func__ << " ICoolingDeviceChangedCallback: " << in_callback;
|
||||
if (in_callback == nullptr) {
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
|
||||
"Invalid nullptr callback");
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> _lock(cdev_callback_mutex_);
|
||||
bool removed = false;
|
||||
cdev_callbacks_.erase(
|
||||
std::remove_if(cdev_callbacks_.begin(), cdev_callbacks_.end(),
|
||||
[&](const std::shared_ptr<ICoolingDeviceChangedCallback>& c) {
|
||||
if (interfacesEqual(c, in_callback)) {
|
||||
removed = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
cdev_callbacks_.end());
|
||||
if (!removed) {
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
|
||||
"Callback wasn't registered");
|
||||
}
|
||||
}
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
} // namespace aidl::android::hardware::thermal::impl::example
|
||||
|
|
|
@ -46,6 +46,7 @@ class Thermal : public BnThermal {
|
|||
|
||||
ndk::ScopedAStatus registerThermalChangedCallback(
|
||||
const std::shared_ptr<IThermalChangedCallback>& in_callback) override;
|
||||
|
||||
ndk::ScopedAStatus registerThermalChangedCallbackWithType(
|
||||
const std::shared_ptr<IThermalChangedCallback>& in_callback,
|
||||
TemperatureType in_type) override;
|
||||
|
@ -53,9 +54,18 @@ class Thermal : public BnThermal {
|
|||
ndk::ScopedAStatus unregisterThermalChangedCallback(
|
||||
const std::shared_ptr<IThermalChangedCallback>& in_callback) override;
|
||||
|
||||
ndk::ScopedAStatus registerCoolingDeviceChangedCallbackWithType(
|
||||
const std::shared_ptr<ICoolingDeviceChangedCallback>& in_callback,
|
||||
CoolingType in_type) override;
|
||||
|
||||
ndk::ScopedAStatus unregisterCoolingDeviceChangedCallback(
|
||||
const std::shared_ptr<ICoolingDeviceChangedCallback>& in_callback) override;
|
||||
|
||||
private:
|
||||
std::mutex thermal_callback_mutex_;
|
||||
std::vector<std::shared_ptr<IThermalChangedCallback>> thermal_callbacks_;
|
||||
std::mutex cdev_callback_mutex_;
|
||||
std::vector<std::shared_ptr<ICoolingDeviceChangedCallback>> cdev_callbacks_;
|
||||
};
|
||||
|
||||
} // namespace example
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include <aidl/Gtest.h>
|
||||
#include <aidl/Vintf.h>
|
||||
#include <aidl/android/hardware/thermal/BnCoolingDeviceChangedCallback.h>
|
||||
#include <aidl/android/hardware/thermal/BnThermal.h>
|
||||
#include <aidl/android/hardware/thermal/BnThermalChangedCallback.h>
|
||||
#include <android-base/logging.h>
|
||||
|
@ -59,6 +60,15 @@ static const Temperature kThrottleTemp = {
|
|||
.throttlingStatus = ThrottlingSeverity::CRITICAL,
|
||||
};
|
||||
|
||||
static const CoolingDevice kCoolingDevice = {
|
||||
.type = CoolingType::CPU,
|
||||
.name = "test cooling device",
|
||||
.value = 1,
|
||||
.powerLimitMw = 300,
|
||||
.powerMw = 500,
|
||||
.timeWindowMs = 7000,
|
||||
};
|
||||
|
||||
// Callback class for receiving thermal event notifications from main class
|
||||
class ThermalCallback : public BnThermalChangedCallback {
|
||||
public:
|
||||
|
@ -85,6 +95,33 @@ class ThermalCallback : public BnThermalChangedCallback {
|
|||
bool mInvoke = false;
|
||||
};
|
||||
|
||||
// Callback class for receiving cooling device event notifications from main class
|
||||
class CoolingDeviceCallback : public BnCoolingDeviceChangedCallback {
|
||||
public:
|
||||
ndk::ScopedAStatus notifyCoolingDeviceChanged(const CoolingDevice&) override {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
mInvoke = true;
|
||||
}
|
||||
mNotifyCoolingDeviceChanged.notify_all();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
template <typename R, typename P>
|
||||
[[nodiscard]] bool waitForCallback(std::chrono::duration<R, P> duration) {
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
bool r = mNotifyCoolingDeviceChanged.wait_for(lock, duration,
|
||||
[this] { return this->mInvoke; });
|
||||
mInvoke = false;
|
||||
return r;
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex mMutex;
|
||||
std::condition_variable mNotifyCoolingDeviceChanged;
|
||||
bool mInvoke = false;
|
||||
};
|
||||
|
||||
// The main test class for THERMAL HIDL HAL.
|
||||
class ThermalAidlTest : public testing::TestWithParam<std::string> {
|
||||
public:
|
||||
|
@ -97,19 +134,42 @@ class ThermalAidlTest : public testing::TestWithParam<std::string> {
|
|||
ASSERT_NE(mThermalCallback, nullptr);
|
||||
::ndk::ScopedAStatus status = mThermal->registerThermalChangedCallback(mThermalCallback);
|
||||
ASSERT_TRUE(status.isOk()) << status.getMessage();
|
||||
|
||||
auto ret = mThermal->getInterfaceVersion(&thermal_version);
|
||||
ASSERT_TRUE(ret.isOk()) << ret;
|
||||
if (thermal_version > 1) {
|
||||
mCoolingDeviceCallback = ndk::SharedRefBase::make<CoolingDeviceCallback>();
|
||||
ASSERT_NE(mCoolingDeviceCallback, nullptr);
|
||||
status = mThermal->registerCoolingDeviceChangedCallbackWithType(mCoolingDeviceCallback,
|
||||
kCoolingDevice.type);
|
||||
ASSERT_TRUE(status.isOk()) << status.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
::ndk::ScopedAStatus status = mThermal->unregisterThermalChangedCallback(mThermalCallback);
|
||||
ASSERT_TRUE(status.isOk()) << status.getMessage();
|
||||
|
||||
// Expect to fail if unregister again
|
||||
status = mThermal->unregisterThermalChangedCallback(mThermalCallback);
|
||||
ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
|
||||
|
||||
auto ret = mThermal->getInterfaceVersion(&thermal_version);
|
||||
ASSERT_TRUE(ret.isOk()) << ret;
|
||||
if (thermal_version > 1) {
|
||||
status = mThermal->unregisterCoolingDeviceChangedCallback(mCoolingDeviceCallback);
|
||||
ASSERT_TRUE(status.isOk()) << status.getMessage();
|
||||
status = mThermal->unregisterCoolingDeviceChangedCallback(mCoolingDeviceCallback);
|
||||
ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
|
||||
}
|
||||
}
|
||||
// Stores thermal version
|
||||
int32_t thermal_version;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<IThermal> mThermal;
|
||||
std::shared_ptr<ThermalCallback> mThermalCallback;
|
||||
std::shared_ptr<CoolingDeviceCallback> mCoolingDeviceCallback;
|
||||
};
|
||||
|
||||
// Test ThermalChangedCallback::notifyThrottling().
|
||||
|
@ -121,6 +181,21 @@ TEST_P(ThermalAidlTest, NotifyThrottlingTest) {
|
|||
ASSERT_TRUE(thermalCallback->waitForCallback(200ms));
|
||||
}
|
||||
|
||||
// Test CoolingDeviceChangedCallback::notifyCoolingDeviceChanged().
|
||||
// This just calls into and back from our local CoolingDeviceChangedCallback impl.
|
||||
TEST_P(ThermalAidlTest, NotifyCoolingDeviceChangedTest) {
|
||||
auto ret = mThermal->getInterfaceVersion(&thermal_version);
|
||||
ASSERT_TRUE(ret.isOk()) << ret;
|
||||
if (thermal_version < 2) {
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<CoolingDeviceCallback> cdevCallback =
|
||||
ndk::SharedRefBase::make<CoolingDeviceCallback>();
|
||||
::ndk::ScopedAStatus status = cdevCallback->notifyCoolingDeviceChanged(kCoolingDevice);
|
||||
ASSERT_TRUE(status.isOk()) << status.getMessage();
|
||||
ASSERT_TRUE(cdevCallback->waitForCallback(200ms));
|
||||
}
|
||||
|
||||
// Test Thermal->registerThermalChangedCallback.
|
||||
TEST_P(ThermalAidlTest, RegisterThermalChangedCallbackTest) {
|
||||
// Expect to fail with same callback
|
||||
|
@ -169,6 +244,37 @@ TEST_P(ThermalAidlTest, RegisterThermalChangedCallbackWithTypeTest) {
|
|||
|| status.getExceptionCode() == EX_NULL_POINTER);
|
||||
}
|
||||
|
||||
// Test Thermal->registerCoolingDeviceChangedCallbackWithType.
|
||||
TEST_P(ThermalAidlTest, RegisterCoolingDeviceChangedCallbackWithTypeTest) {
|
||||
auto ret = mThermal->getInterfaceVersion(&thermal_version);
|
||||
ASSERT_TRUE(ret.isOk()) << ret;
|
||||
if (thermal_version < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Expect to fail with same callback
|
||||
::ndk::ScopedAStatus status = mThermal->registerCoolingDeviceChangedCallbackWithType(
|
||||
mCoolingDeviceCallback, CoolingType::CPU);
|
||||
ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
|
||||
// Expect to fail with null callback
|
||||
status = mThermal->registerCoolingDeviceChangedCallbackWithType(nullptr, CoolingType::CPU);
|
||||
ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT ||
|
||||
status.getExceptionCode() == EX_NULL_POINTER);
|
||||
std::shared_ptr<CoolingDeviceCallback> localCoolingDeviceCallback =
|
||||
ndk::SharedRefBase::make<CoolingDeviceCallback>();
|
||||
// Expect to succeed with different callback
|
||||
status = mThermal->registerCoolingDeviceChangedCallbackWithType(localCoolingDeviceCallback,
|
||||
CoolingType::CPU);
|
||||
ASSERT_TRUE(status.isOk()) << status.getMessage();
|
||||
// Remove the local callback
|
||||
status = mThermal->unregisterCoolingDeviceChangedCallback(localCoolingDeviceCallback);
|
||||
ASSERT_TRUE(status.isOk()) << status.getMessage();
|
||||
// Expect to fail with null callback
|
||||
status = mThermal->unregisterCoolingDeviceChangedCallback(nullptr);
|
||||
ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT ||
|
||||
status.getExceptionCode() == EX_NULL_POINTER);
|
||||
}
|
||||
|
||||
// Test Thermal->getCurrentTemperatures().
|
||||
TEST_P(ThermalAidlTest, TemperatureTest) {
|
||||
std::vector<Temperature> ret;
|
||||
|
|
Loading…
Reference in a new issue