summaryrefslogtreecommitdiff
path: root/native/android/thermal.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'native/android/thermal.cpp')
-rw-r--r--native/android/thermal.cpp323
1 files changed, 192 insertions, 131 deletions
diff --git a/native/android/thermal.cpp b/native/android/thermal.cpp
index f7a3537d3f4a..cefcaf7766bb 100644
--- a/native/android/thermal.cpp
+++ b/native/android/thermal.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "thermal"
#include <android-base/thread_annotations.h>
+#include <android/os/BnThermalHeadroomListener.h>
#include <android/os/BnThermalStatusListener.h>
#include <android/os/IThermalService.h>
#include <android/thermal.h>
@@ -33,10 +34,10 @@ using android::sp;
using namespace android;
using namespace android::os;
-struct ThermalServiceListener : public BnThermalStatusListener {
+struct ThermalServiceStatusListener : public BnThermalStatusListener {
public:
virtual binder::Status onStatusChange(int32_t status) override;
- ThermalServiceListener(AThermalManager *manager) {
+ ThermalServiceStatusListener(AThermalManager *manager) {
mMgr = manager;
}
@@ -44,11 +45,29 @@ private:
AThermalManager *mMgr;
};
-struct ListenerCallback {
+struct ThermalServiceHeadroomListener : public BnThermalHeadroomListener {
+public:
+ virtual binder::Status onHeadroomChange(float headroom, float forecastHeadroom,
+ int32_t forecastSeconds,
+ const ::std::vector<float> &thresholds) override;
+ ThermalServiceHeadroomListener(AThermalManager *manager) {
+ mMgr = manager;
+ }
+
+private:
+ AThermalManager *mMgr;
+};
+
+struct StatusListenerCallback {
AThermal_StatusCallback callback;
void* data;
};
+struct HeadroomListenerCallback {
+ AThermal_HeadroomCallback callback;
+ void *data;
+};
+
static IThermalService *gIThermalServiceForTesting = nullptr;
struct AThermalManager {
@@ -57,30 +76,44 @@ public:
AThermalManager() = delete;
~AThermalManager();
status_t notifyStateChange(int32_t status);
+ status_t notifyHeadroomChange(float headroom, float forecastHeadroom, int32_t forecastSeconds,
+ const ::std::vector<float> &thresholds);
status_t getCurrentThermalStatus(int32_t *status);
- status_t addListener(AThermal_StatusCallback, void *data);
- status_t removeListener(AThermal_StatusCallback, void *data);
+ status_t addStatusListener(AThermal_StatusCallback, void *data);
+ status_t removeStatusListener(AThermal_StatusCallback, void *data);
status_t getThermalHeadroom(int32_t forecastSeconds, float *result);
status_t getThermalHeadroomThresholds(const AThermalHeadroomThreshold **, size_t *size);
+ status_t addHeadroomListener(AThermal_HeadroomCallback, void *data);
+ status_t removeHeadroomListener(AThermal_HeadroomCallback, void *data);
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);
+ std::mutex mStatusListenerMutex;
+ sp<ThermalServiceStatusListener> mServiceStatusListener GUARDED_BY(mStatusListenerMutex);
+ std::vector<StatusListenerCallback> mStatusListeners GUARDED_BY(mStatusListenerMutex);
+
+ std::mutex mHeadroomListenerMutex;
+ sp<ThermalServiceHeadroomListener> mServiceHeadroomListener GUARDED_BY(mHeadroomListenerMutex);
+ std::vector<HeadroomListenerCallback> mHeadroomListeners GUARDED_BY(mHeadroomListenerMutex);
};
-binder::Status ThermalServiceListener::onStatusChange(int32_t status) {
+binder::Status ThermalServiceStatusListener::onStatusChange(int32_t status) {
if (mMgr != nullptr) {
mMgr->notifyStateChange(status);
}
return binder::Status::ok();
}
+binder::Status ThermalServiceHeadroomListener::onHeadroomChange(
+ float headroom, float forecastHeadroom, int32_t forecastSeconds,
+ const ::std::vector<float> &thresholds) {
+ if (mMgr != nullptr) {
+ mMgr->notifyHeadroomChange(headroom, forecastHeadroom, forecastSeconds, thresholds);
+ }
+ return binder::Status::ok();
+}
+
AThermalManager* AThermalManager::createAThermalManager() {
if (gIThermalServiceForTesting) {
return new AThermalManager(gIThermalServiceForTesting);
@@ -96,97 +129,183 @@ AThermalManager* AThermalManager::createAThermalManager() {
}
AThermalManager::AThermalManager(sp<IThermalService> service)
- : mThermalSvc(std::move(service)), mServiceListener(nullptr) {}
+ : mThermalSvc(std::move(service)),
+ mServiceStatusListener(nullptr),
+ mServiceHeadroomListener(nullptr) {}
AThermalManager::~AThermalManager() {
{
- std::scoped_lock<std::mutex> listenerLock(mListenerMutex);
- mListeners.clear();
- if (mServiceListener != nullptr) {
+ std::scoped_lock<std::mutex> listenerLock(mStatusListenerMutex);
+ mStatusListeners.clear();
+ if (mServiceStatusListener != nullptr) {
bool success = false;
- mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success);
- mServiceListener = nullptr;
+ mThermalSvc->unregisterThermalStatusListener(mServiceStatusListener, &success);
+ mServiceStatusListener = nullptr;
+ }
+ }
+ {
+ std::scoped_lock<std::mutex> headroomListenerLock(mHeadroomListenerMutex);
+ mHeadroomListeners.clear();
+ if (mServiceHeadroomListener != nullptr) {
+ bool success = false;
+ mThermalSvc->unregisterThermalHeadroomListener(mServiceHeadroomListener, &success);
+ mServiceHeadroomListener = nullptr;
}
}
- std::scoped_lock<std::mutex> lock(mThresholdsMutex);
- delete[] mThresholds;
}
status_t AThermalManager::notifyStateChange(int32_t status) {
- std::scoped_lock<std::mutex> lock(mListenerMutex);
+ std::scoped_lock<std::mutex> lock(mStatusListenerMutex);
AThermalStatus thermalStatus = static_cast<AThermalStatus>(status);
- for (auto listener : mListeners) {
+ for (auto listener : mStatusListeners) {
listener.callback(listener.data, thermalStatus);
}
return OK;
}
-status_t AThermalManager::addListener(AThermal_StatusCallback callback, void *data) {
- std::scoped_lock<std::mutex> lock(mListenerMutex);
+status_t AThermalManager::notifyHeadroomChange(float headroom, float forecastHeadroom,
+ int32_t forecastSeconds,
+ const ::std::vector<float> &thresholds) {
+ std::scoped_lock<std::mutex> lock(mHeadroomListenerMutex);
+ size_t thresholdsCount = thresholds.size();
+ auto t = new AThermalHeadroomThreshold[thresholdsCount];
+ for (int i = 0; i < (int)thresholdsCount; i++) {
+ t[i].headroom = thresholds[i];
+ t[i].thermalStatus = static_cast<AThermalStatus>(i);
+ }
+ for (auto listener : mHeadroomListeners) {
+ listener.callback(listener.data, headroom, forecastHeadroom, forecastSeconds, t,
+ thresholdsCount);
+ }
+ delete[] t;
+ return OK;
+}
+
+status_t AThermalManager::addStatusListener(AThermal_StatusCallback callback, void *data) {
+ std::scoped_lock<std::mutex> lock(mStatusListenerMutex);
if (callback == nullptr) {
// Callback can not be nullptr
return EINVAL;
}
- for (const auto& cb : mListeners) {
+ for (const auto &cb : mStatusListeners) {
// Don't re-add callbacks.
if (callback == cb.callback && data == cb.data) {
return EINVAL;
}
}
- mListeners.emplace_back(ListenerCallback{callback, data});
- if (mServiceListener != nullptr) {
+ if (mServiceStatusListener != nullptr) {
+ mStatusListeners.emplace_back(StatusListenerCallback{callback, data});
return OK;
}
bool success = false;
- mServiceListener = new ThermalServiceListener(this);
- if (mServiceListener == nullptr) {
+ mServiceStatusListener = new ThermalServiceStatusListener(this);
+ if (mServiceStatusListener == nullptr) {
return ENOMEM;
}
- auto ret = mThermalSvc->registerThermalStatusListener(mServiceListener, &success);
+ auto ret = mThermalSvc->registerThermalStatusListener(mServiceStatusListener, &success);
if (!success || !ret.isOk()) {
+ mServiceStatusListener = nullptr;
ALOGE("Failed in registerThermalStatusListener %d", success);
if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
return EPERM;
}
return EPIPE;
}
+ mStatusListeners.emplace_back(StatusListenerCallback{callback, data});
return OK;
}
-status_t AThermalManager::removeListener(AThermal_StatusCallback callback, void *data) {
- std::scoped_lock<std::mutex> lock(mListenerMutex);
+status_t AThermalManager::removeStatusListener(AThermal_StatusCallback callback, void *data) {
+ std::scoped_lock<std::mutex> lock(mStatusListenerMutex);
- auto it = std::remove_if(mListeners.begin(),
- mListeners.end(),
- [&](const ListenerCallback& cb) {
- return callback == cb.callback &&
- data == cb.data;
+ auto it = std::remove_if(mStatusListeners.begin(), mStatusListeners.end(),
+ [&](const StatusListenerCallback &cb) {
+ return callback == cb.callback && data == cb.data;
});
- if (it == mListeners.end()) {
+ if (it == mStatusListeners.end()) {
// If the listener and data pointer were not previously added.
return EINVAL;
}
- mListeners.erase(it, mListeners.end());
+ if (mServiceStatusListener == nullptr || mStatusListeners.size() > 1) {
+ mStatusListeners.erase(it, mStatusListeners.end());
+ return OK;
+ }
- if (!mListeners.empty()) {
+ bool success = false;
+ auto ret = mThermalSvc->unregisterThermalStatusListener(mServiceStatusListener, &success);
+ if (!success || !ret.isOk()) {
+ ALOGE("Failed in unregisterThermalStatusListener %d", success);
+ if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
+ return EPERM;
+ }
+ return EPIPE;
+ }
+ mServiceStatusListener = nullptr;
+ mStatusListeners.erase(it, mStatusListeners.end());
+ return OK;
+}
+
+status_t AThermalManager::addHeadroomListener(AThermal_HeadroomCallback callback, void *data) {
+ std::scoped_lock<std::mutex> lock(mHeadroomListenerMutex);
+ if (callback == nullptr) {
+ return EINVAL;
+ }
+ for (const auto &cb : mHeadroomListeners) {
+ if (callback == cb.callback && data == cb.data) {
+ return EINVAL;
+ }
+ }
+
+ if (mServiceHeadroomListener != nullptr) {
+ mHeadroomListeners.emplace_back(HeadroomListenerCallback{callback, data});
return OK;
}
- if (mServiceListener == nullptr) {
+ bool success = false;
+ mServiceHeadroomListener = new ThermalServiceHeadroomListener(this);
+ if (mServiceHeadroomListener == nullptr) {
+ return ENOMEM;
+ }
+ auto ret = mThermalSvc->registerThermalHeadroomListener(mServiceHeadroomListener, &success);
+ if (!success || !ret.isOk()) {
+ ALOGE("Failed in registerThermalHeadroomListener %d", success);
+ mServiceHeadroomListener = nullptr;
+ if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
+ return EPERM;
+ }
+ return EPIPE;
+ }
+ mHeadroomListeners.emplace_back(HeadroomListenerCallback{callback, data});
+ return OK;
+}
+
+status_t AThermalManager::removeHeadroomListener(AThermal_HeadroomCallback callback, void *data) {
+ std::scoped_lock<std::mutex> lock(mHeadroomListenerMutex);
+
+ auto it = std::remove_if(mHeadroomListeners.begin(), mHeadroomListeners.end(),
+ [&](const HeadroomListenerCallback &cb) {
+ return callback == cb.callback && data == cb.data;
+ });
+ if (it == mHeadroomListeners.end()) {
+ return EINVAL;
+ }
+ if (mServiceHeadroomListener == nullptr || mHeadroomListeners.size() > 1) {
+ mHeadroomListeners.erase(it, mHeadroomListeners.end());
return OK;
}
bool success = false;
- auto ret = mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success);
+ auto ret = mThermalSvc->unregisterThermalHeadroomListener(mServiceHeadroomListener, &success);
if (!success || !ret.isOk()) {
- ALOGE("Failed in unregisterThermalStatusListener %d", success);
+ ALOGE("Failed in unregisterThermalHeadroomListener %d", success);
if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
return EPERM;
}
return EPIPE;
}
- mServiceListener = nullptr;
+ mServiceHeadroomListener = nullptr;
+ mHeadroomListeners.erase(it, mHeadroomListeners.end());
return OK;
}
@@ -216,61 +335,36 @@ status_t AThermalManager::getThermalHeadroom(int32_t forecastSeconds, float *res
status_t AThermalManager::getThermalHeadroomThresholds(const AThermalHeadroomThreshold **result,
size_t *size) {
- std::scoped_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);
+ 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;
}
- mThresholds = t;
+ return EPIPE;
+ }
+ size_t thresholdsCount = thresholds->size();
+ auto t = new AThermalHeadroomThreshold[thresholdsCount];
+ for (int i = 0; i < (int)thresholdsCount; i++) {
+ t[i].headroom = (*thresholds)[i];
+ t[i].thermalStatus = static_cast<AThermalStatus>(i);
}
- *size = mThresholdsCount;
- *result = mThresholds;
+ *size = thresholdsCount;
+ *result = t;
return OK;
}
-/**
- * Acquire an instance of the thermal manager. This must be freed using
- * {@link AThermal_releaseManager}.
- *
- * @return manager instance on success, nullptr on failure.
- */
AThermalManager* AThermal_acquireManager() {
auto manager = AThermalManager::createAThermalManager();
return manager;
}
-/**
- * Release the thermal manager pointer acquired by
- * {@link AThermal_acquireManager}.
- *
- * @param manager The manager to be released.
- *
- */
void AThermal_releaseManager(AThermalManager *manager) {
delete manager;
}
-/**
- * Gets the current thermal status.
- *
- * @param manager The manager instance to use to query the thermal status,
- * acquired by {@link AThermal_acquireManager}.
- *
- * @return current thermal status, ATHERMAL_STATUS_ERROR on failure.
-*/
AThermalStatus AThermal_getCurrentThermalStatus(AThermalManager *manager) {
int32_t status = 0;
status_t ret = manager->getCurrentThermalStatus(&status);
@@ -280,59 +374,16 @@ AThermalStatus AThermal_getCurrentThermalStatus(AThermalManager *manager) {
return static_cast<AThermalStatus>(status);
}
-/**
- * Register the thermal status listener for thermal status change.
- *
- * @param manager The manager instance to use to register.
- * acquired by {@link AThermal_acquireManager}.
- * @param callback The callback function to be called when thermal status updated.
- * @param data The data pointer to be passed when callback is called.
- *
- * @return 0 on success
- * EINVAL if the listener and data pointer were previously added and not removed.
- * EPERM if the required permission is not held.
- * EPIPE if communication with the system service has failed.
- */
int AThermal_registerThermalStatusListener(AThermalManager *manager,
- AThermal_StatusCallback callback, void *data) {
- return manager->addListener(callback, data);
+ AThermal_StatusCallback callback, void *data) {
+ return manager->addStatusListener(callback, data);
}
-/**
- * Unregister the thermal status listener previously resgistered.
- *
- * @param manager The manager instance to use to unregister.
- * acquired by {@link AThermal_acquireManager}.
- * @param callback The callback function to be called when thermal status updated.
- * @param data The data pointer to be passed when callback is called.
- *
- * @return 0 on success
- * EINVAL if the listener and data pointer were not previously added.
- * EPERM if the required permission is not held.
- * EPIPE if communication with the system service has failed.
- */
int AThermal_unregisterThermalStatusListener(AThermalManager *manager,
- AThermal_StatusCallback callback, void *data) {
- return manager->removeListener(callback, data);
+ AThermal_StatusCallback callback, void *data) {
+ return manager->removeStatusListener(callback, data);
}
-/**
- * Provides an estimate of how much thermal headroom the device currently has
- * before hitting severe throttling.
- *
- * Note that this only attempts to track the headroom of slow-moving sensors,
- * such as the skin temperature sensor. This means that there is no benefit to
- * calling this function more frequently than about once per second, and attempts
- * to call significantly more frequently may result in the function returning {@code NaN}.
- *
- * See also PowerManager#getThermalHeadroom.
- *
- * @param manager The manager instance to use
- * @param forecastSeconds how many seconds in the future to forecast
- * @return a value greater than or equal to 0.0 where 1.0 indicates the SEVERE throttling
- * 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 result = 0.0f;
status_t ret = manager->getThermalHeadroom(forecastSeconds, &result);
@@ -354,3 +405,13 @@ int AThermal_getThermalHeadroomThresholds(AThermalManager *manager,
void AThermal_setIThermalServiceForTesting(void *iThermalService) {
gIThermalServiceForTesting = static_cast<IThermalService *>(iThermalService);
}
+
+int AThermal_registerThermalHeadroomListener(AThermalManager *manager,
+ AThermal_HeadroomCallback callback, void *data) {
+ return manager->addHeadroomListener(callback, data);
+}
+
+int AThermal_unregisterThermalHeadroomListener(AThermalManager *manager,
+ AThermal_HeadroomCallback callback, void *data) {
+ return manager->removeHeadroomListener(callback, data);
+}