Add NDK API AThermal_getThermalHeadroomThresholds
Bug: b/288119641
Test: atest NativeThermalUnitTestCases
Change-Id: I2ba820da74b290a25ff1edf8d278b9200dfaf950
diff --git a/native/android/thermal.cpp b/native/android/thermal.cpp
index 1f6ef47..b43f2f16 100644
--- a/native/android/thermal.cpp
+++ b/native/android/thermal.cpp
@@ -16,27 +16,32 @@
#define LOG_TAG "thermal"
-#include <cerrno>
-#include <thread>
-#include <limits>
-
-#include <android/thermal.h>
+#include <android-base/thread_annotations.h>
#include <android/os/BnThermalStatusListener.h>
#include <android/os/IThermalService.h>
+#include <android/thermal.h>
#include <binder/IServiceManager.h>
+#include <thermal_private.h>
#include <utils/Log.h>
+#include <cerrno>
+#include <limits>
+#include <thread>
+
using android::sp;
using namespace android;
using namespace android::os;
struct ThermalServiceListener : public BnThermalStatusListener {
- public:
- virtual binder::Status onStatusChange(int32_t status) override;
- ThermalServiceListener(AThermalManager *manager) {mMgr = manager;}
- private:
- AThermalManager *mMgr;
+public:
+ virtual binder::Status onStatusChange(int32_t status) override;
+ ThermalServiceListener(AThermalManager *manager) {
+ mMgr = manager;
+ }
+
+private:
+ AThermalManager *mMgr;
};
struct ListenerCallback {
@@ -44,22 +49,29 @@
void* data;
};
+static IThermalService *gIThermalServiceForTesting = nullptr;
+
struct AThermalManager {
- public:
- static AThermalManager* createAThermalManager();
- AThermalManager() = delete;
- ~AThermalManager();
- status_t notifyStateChange(int32_t status);
- status_t getCurrentThermalStatus(int32_t *status);
- status_t addListener(AThermal_StatusCallback, void *data);
- status_t removeListener(AThermal_StatusCallback, void *data);
- status_t getThermalHeadroom(int32_t forecastSeconds, float *result);
- private:
- AThermalManager(sp<IThermalService> service);
- sp<IThermalService> mThermalSvc;
- sp<ThermalServiceListener> mServiceListener;
- std::vector<ListenerCallback> mListeners;
- std::mutex mMutex;
+public:
+ static AThermalManager *createAThermalManager();
+ AThermalManager() = delete;
+ ~AThermalManager();
+ status_t notifyStateChange(int32_t status);
+ status_t getCurrentThermalStatus(int32_t *status);
+ status_t addListener(AThermal_StatusCallback, void *data);
+ status_t removeListener(AThermal_StatusCallback, void *data);
+ status_t getThermalHeadroom(int32_t forecastSeconds, float *result);
+ status_t getThermalHeadroomThresholds(const AThermalHeadroomThreshold **, size_t *size);
+
+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);
};
binder::Status ThermalServiceListener::onStatusChange(int32_t status) {
@@ -70,6 +82,9 @@
}
AThermalManager* AThermalManager::createAThermalManager() {
+ if (gIThermalServiceForTesting) {
+ return new AThermalManager(gIThermalServiceForTesting);
+ }
sp<IBinder> binder =
defaultServiceManager()->checkService(String16("thermalservice"));
@@ -81,12 +96,10 @@
}
AThermalManager::AThermalManager(sp<IThermalService> service)
- : mThermalSvc(service),
- mServiceListener(nullptr) {
-}
+ : mThermalSvc(std::move(service)), mServiceListener(nullptr) {}
AThermalManager::~AThermalManager() {
- std::unique_lock<std::mutex> lock(mMutex);
+ std::unique_lock<std::mutex> listenerLock(mListenerMutex);
mListeners.clear();
if (mServiceListener != nullptr) {
@@ -94,10 +107,13 @@
mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success);
mServiceListener = nullptr;
}
+ listenerLock.unlock();
+ std::unique_lock<std::mutex> lock(mThresholdsMutex);
+ delete[] mThresholds;
}
status_t AThermalManager::notifyStateChange(int32_t status) {
- std::unique_lock<std::mutex> lock(mMutex);
+ std::unique_lock<std::mutex> lock(mListenerMutex);
AThermalStatus thermalStatus = static_cast<AThermalStatus>(status);
for (auto listener : mListeners) {
@@ -107,7 +123,7 @@
}
status_t AThermalManager::addListener(AThermal_StatusCallback callback, void *data) {
- std::unique_lock<std::mutex> lock(mMutex);
+ std::unique_lock<std::mutex> lock(mListenerMutex);
if (callback == nullptr) {
// Callback can not be nullptr
@@ -141,7 +157,7 @@
}
status_t AThermalManager::removeListener(AThermal_StatusCallback callback, void *data) {
- std::unique_lock<std::mutex> lock(mMutex);
+ std::unique_lock<std::mutex> lock(mListenerMutex);
auto it = std::remove_if(mListeners.begin(),
mListeners.end(),
@@ -198,6 +214,32 @@
return OK;
}
+status_t AThermalManager::getThermalHeadroomThresholds(const AThermalHeadroomThreshold **result,
+ size_t *size) {
+ std::unique_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);
+ }
+ mThresholds = t;
+ }
+ *size = mThresholdsCount;
+ *result = mThresholds;
+ return OK;
+}
+
/**
* Acquire an instance of the thermal manager. This must be freed using
* {@link AThermal_releaseManager}.
@@ -291,14 +333,24 @@
* 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 AThermal_getThermalHeadroom(AThermalManager *manager, int forecastSeconds) {
float result = 0.0f;
status_t ret = manager->getThermalHeadroom(forecastSeconds, &result);
-
if (ret != OK) {
result = std::numeric_limits<float>::quiet_NaN();
}
-
return result;
}
+
+int AThermal_getThermalHeadroomThresholds(AThermalManager *manager,
+ const AThermalHeadroomThreshold **outThresholds,
+ size_t *size) {
+ if (outThresholds == nullptr || *outThresholds != nullptr || size == nullptr) {
+ return EINVAL;
+ }
+ return manager->getThermalHeadroomThresholds(outThresholds, size);
+}
+
+void AThermal_setIThermalServiceForTesting(void *iThermalService) {
+ gIThermalServiceForTesting = static_cast<IThermalService *>(iThermalService);
+}