diff options
| author | 2020-01-15 10:51:47 -0800 | |
|---|---|---|
| committer | 2020-02-19 13:50:06 -0800 | |
| commit | 1a5a8886102e0b5a76c52ed0d91a4e0631fbf243 (patch) | |
| tree | 9386ed733c286683215113b76a921a8703c3e0f9 | |
| parent | 31cf0a0d5a9c722e1a86f57963e5e8dd0e1bef76 (diff) | |
Create native version of Thermal Throttling API.
Create native thermal manager API of thermal mananger service.
Export libthermal NDK library.
Bug: 137151587
Bug: 136285293
Test: build, atest thermalmanager-test
Change-Id: I1ec7c746f7e814c701b306e06fe08c3641c39e88
| -rw-r--r-- | include/android/CoolingDevice.h | 49 | ||||
| -rw-r--r-- | include/android/Temperature.h | 53 | ||||
| -rw-r--r-- | include/android/thermal.h | 182 | ||||
| -rw-r--r-- | include/powermanager/PowerManager.h | 11 | ||||
| -rw-r--r-- | services/powermanager/Android.bp | 35 | ||||
| -rw-r--r-- | services/powermanager/CoolingDevice.cpp | 53 | ||||
| -rw-r--r-- | services/powermanager/IThermalManagerTest.cpp | 158 | ||||
| -rw-r--r-- | services/powermanager/Temperature.cpp | 55 |
8 files changed, 595 insertions, 1 deletions
diff --git a/include/android/CoolingDevice.h b/include/android/CoolingDevice.h new file mode 100644 index 0000000000..2f366be544 --- /dev/null +++ b/include/android/CoolingDevice.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2020 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. + */ + +#ifndef ANDROID_OS_COOLINGDEVICE_H +#define ANDROID_OS_COOLINGDEVICE_H + +#include <binder/Parcelable.h> +#include <utils/RefBase.h> + +namespace android { +namespace os { + +/** + * CoolingDevice is a structure to encapsulate cooling device status. + */ +struct CoolingDevice : public android::Parcelable { + /** Current throttle state of the cooling device. */ + float mValue; + /** A cooling device type from ThermalHAL */ + uint32_t mType; + /** Name of this cooling device */ + String16 mName; + + CoolingDevice() + : mValue(0.0f), + mType(0), + mName("") { + } + virtual status_t readFromParcel(const android::Parcel* parcel) override; + virtual status_t writeToParcel(android::Parcel* parcel) const override; +}; + +} // namespace os +} // namespace android + +#endif /* ANDROID_OS_COOLINGDEVICE_H */ diff --git a/include/android/Temperature.h b/include/android/Temperature.h new file mode 100644 index 0000000000..2e68ec4899 --- /dev/null +++ b/include/android/Temperature.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2020 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. + */ + +#ifndef ANDROID_OS_TEMPERATURE_H +#define ANDROID_OS_TEMPERATURE_H + +#include <binder/Parcelable.h> +#include <utils/RefBase.h> + +namespace android { +namespace os { + +/** + * Temperature is a structure to encapsulate temperature status. + */ +struct Temperature : public android::Parcelable { + /** Temperature value */ + float mValue; + /** A Temperature type from ThermalHAL */ + int32_t mType; + /** Name of this Temperature */ + String16 mName; + /** The level of the sensor is currently in throttling */ + int32_t mStatus; + + Temperature() + : mValue(0.0f), + mType(0), + mName(""), + mStatus(0) { + } + + virtual status_t readFromParcel(const android::Parcel* parcel) override; + virtual status_t writeToParcel(android::Parcel* parcel) const override; +}; + +} // namespace os +} // namespace android + +#endif /* ANDROID_OS_TEMPERATURE_H */ diff --git a/include/android/thermal.h b/include/android/thermal.h new file mode 100644 index 0000000000..0f4b4d9b8d --- /dev/null +++ b/include/android/thermal.h @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2020 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. + */ + +/** + * @addtogroup Thermal + * @{ + */ + +/** + * @file thermal.h + */ + +#ifndef _ANDROID_THERMAL_H +#define _ANDROID_THERMAL_H + +#include <sys/cdefs.h> + +/****************************************************************** + * + * IMPORTANT NOTICE: + * + * This file is part of Android's set of stable system headers + * exposed by the Android NDK (Native Development Kit). + * + * Third-party source AND binary code relies on the definitions + * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. + * + * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) + * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS + * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY + * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES + */ + +/* + * Structures and functions to access thermal status and register/unregister + * thermal status listener in native code. + */ + +#include <stdint.h> +#include <sys/types.h> + +#if !defined(__INTRODUCED_IN) +#define __INTRODUCED_IN(30) /* Introduced in API level 30 */ +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if __ANDROID_API__ >= 30 + +enum AThermalStatus { + /** Error in thermal status. */ + ATHERMAL_STATUS_ERROR = -1, + /** Not under throttling. */ + ATHERMAL_STATUS_NONE = 0, + /** Light throttling where UX is not impacted. */ + ATHERMAL_STATUS_LIGHT = 1, + /** Moderate throttling where UX is not largely impacted. */ + ATHERMAL_STATUS_MODERATE = 2, + /** Severe throttling where UX is largely impacted. */ + ATHERMAL_STATUS_SEVERE = 3, + /** Platform has done everything to reduce power. */ + ATHERMAL_STATUS_CRITICAL = 4, + /** + * Key components in platform are shutting down due to thermal condition. + * Device functionalities will be limited. + */ + ATHERMAL_STATUS_EMERGENCY = 5, + /** Need shutdown immediately. */ + ATHERMAL_STATUS_SHUTDOWN = 6, +}; + +/** + * An opaque type representing a handle to a thermal manager. + * An instance of thermal manager must be acquired prior to + * using thermal status APIs and must be released after use. + * + * <p>To use:<ul> + * <li>Create a new thermal manager instance by calling the + * {@link AThermal_acquireManager} function.</li> + * <li>Get current thermal status with + * {@link AThermal_getCurrentThermalStatus}.</li> + * <li>Register a thermal status listener with + * {@link AThermal_registerThermalStatusListener}.</li> + * <li>Unregister a thermal status listener with + * {@link AThermal_unregisterThermalStatusListener}.</li> + * <li>Release the thermal manager instance with + * {@link AThermal_releaseManager}.</li></ul></p> + * + */ +typedef struct AThermalManager AThermalManager; + +/** + * Prototype of the function that is called when thermal status changes. + * It's passed the updated thermal status as parameter, as well as the + * pointer provided by the client that registered a callback. + */ +typedef int (*AThermal_StatusCallback)(void *data, AThermalStatus status); + +/** + * 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(); + +/** + * Release the thermal manager pointer acquired via + * {@link AThermal_acquireManager}. + * + * @param manager The manager to be released. + * + */ +void AThermal_releaseManager(AThermalManager *manager); + +/** + * Gets the current thermal status. + * + * @param manager The manager instance to use to query the thermal status. + * Acquired via {@link AThermal_acquireManager}. + * + * @return current thermal status, ATHERMAL_STATUS_ERROR on failure. +*/ +AThermalStatus AThermal_getCurrentThermalStatus(AThermalManager *manager); + +/** + * Register the thermal status listener for thermal status change. + * + * @param manager The manager instance to use to register. + * Acquired via {@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); + +/** + * Unregister the thermal status listener previously resgistered. + * + * @param manager The manager instance to use to unregister. + * Acquired via {@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); + + +#endif // __ANDROID_API__ >= 30 + +#ifdef __cplusplus +} +#endif + +#endif // _ANDROID_THERMAL_H + +/** @} */ diff --git a/include/powermanager/PowerManager.h b/include/powermanager/PowerManager.h index 3268b45716..9bac242a12 100644 --- a/include/powermanager/PowerManager.h +++ b/include/powermanager/PowerManager.h @@ -33,6 +33,17 @@ enum { USER_ACTIVITY_EVENT_LAST = USER_ACTIVITY_EVENT_ACCESSIBILITY, // Last valid event code. }; +/** Keep in sync with android.os.temprature and hardware/interfaces/thermal/2.0/types.hal */ +enum class ThermalStatus : uint32_t { + THERMAL_STATUS_NONE = 0, + THERMAL_STATUS_LIGHT = 1, + THERMAL_STATUS_MODERATE = 2, + THERMAL_STATUS_SEVERE = 3, + THERMAL_STATUS_CRITICAL = 4, + THERMAL_STATUS_EMERGENCY = 5, + THERMAL_STATUS_SHUTDOWN = 6, +}; + }; // namespace android #endif // ANDROID_POWERMANAGER_H diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp index 7b3af70927..3e0f136dfb 100644 --- a/services/powermanager/Android.bp +++ b/services/powermanager/Android.bp @@ -1,11 +1,25 @@ cc_library_shared { name: "libpowermanager", - srcs: ["IPowerManager.cpp"], + srcs: [ + "IPowerManager.cpp", + "Temperature.cpp", + "CoolingDevice.cpp", + ":libpowermanager_aidl", + ], + + aidl: { + local_include_dirs: ["."], + include_dirs: [ + "frameworks/base/core/java/android/os", + ], + export_aidl_headers: true + }, shared_libs: [ "libutils", "libbinder", + "liblog" ], cflags: [ @@ -15,3 +29,22 @@ cc_library_shared { "-Wunreachable-code", ], } + +cc_test { + name: "thermalmanager-test", + srcs: ["IThermalManagerTest.cpp", + ], + cflags: [ + "-Wall", + "-Werror", + "-Wextra", + ], + shared_libs: [ + "libbase", + "libhidlbase", + "liblog", + "libpowermanager", + "libbinder", + "libutils", + ], +} diff --git a/services/powermanager/CoolingDevice.cpp b/services/powermanager/CoolingDevice.cpp new file mode 100644 index 0000000000..ebbc1b4197 --- /dev/null +++ b/services/powermanager/CoolingDevice.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2020 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 "CoolingDevice" + +#include <android/CoolingDevice.h> +#include <binder/Parcel.h> +#include <utils/Log.h> + +namespace android { +namespace os { + +status_t CoolingDevice::readFromParcel(const android::Parcel *parcel) { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __FUNCTION__); + return BAD_VALUE; + } + + parcel->readFloat(&mValue); + parcel->readUint32(&mType); + parcel->readString16(&mName); + + return OK; +} + +status_t CoolingDevice::writeToParcel(android::Parcel *parcel) const { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __FUNCTION__); + return BAD_VALUE; + } + + parcel->writeFloat(mValue); + parcel->writeUint32(mType); + parcel->writeString16(mName); + + return OK; +} + +} // namespace os +} // namespace android
\ No newline at end of file diff --git a/services/powermanager/IThermalManagerTest.cpp b/services/powermanager/IThermalManagerTest.cpp new file mode 100644 index 0000000000..575b9ee1c4 --- /dev/null +++ b/services/powermanager/IThermalManagerTest.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2020 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 "ThermalManagerTest" +//#define LOG_NDEBUG 0 + +#include <thread> + +#include <android/os/BnThermalStatusListener.h> +#include <android/os/IThermalService.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/Parcel.h> +#include <condition_variable> +#include <gtest/gtest.h> +#include <powermanager/PowerManager.h> +#include <utils/Log.h> + +using namespace android; +using namespace android::os; +using namespace std::chrono_literals; + +class IThermalServiceTest : public testing::Test, + public BnThermalStatusListener{ + public: + IThermalServiceTest(); + void setThermalOverride(int level); + virtual binder::Status onStatusChange(int status) override; + int getStatusFromService(); + void SetUp() override; + void TearDown() override; + protected: + sp<IThermalService> mThermalSvc; + std::condition_variable mCondition; + int mListenerStatus; + int mServiceStatus; + std::mutex mMutex; +}; + +IThermalServiceTest::IThermalServiceTest() + : mListenerStatus(0), + mServiceStatus(0) { +} + +void IThermalServiceTest::setThermalOverride(int level) { + std::string cmdStr = "cmd thermalservice override-status " + std::to_string(level); + system(cmdStr.c_str()); +} + +binder::Status IThermalServiceTest::onStatusChange(int status) { + std::unique_lock<std::mutex> lock(mMutex); + mListenerStatus = status; + ALOGI("IThermalServiceTest::notifyListener %d", mListenerStatus); + mCondition.notify_all(); + return binder::Status::ok(); +} + +int IThermalServiceTest::getStatusFromService() { + int status; + binder::Status ret = mThermalSvc->getCurrentThermalStatus(&status); + if (ret.isOk()) { + return status; + } else { + return BAD_VALUE; + } +} + +void IThermalServiceTest::SetUp() { + setThermalOverride(0); + // use checkService() to avoid blocking if thermal service is not up yet + sp<IBinder> binder = + defaultServiceManager()->checkService(String16("thermalservice")); + EXPECT_NE(binder, nullptr); + mThermalSvc = interface_cast<IThermalService>(binder); + EXPECT_NE(mThermalSvc, nullptr); + bool success = false; + binder::Status ret = mThermalSvc->registerThermalStatusListener(this, &success); + ASSERT_TRUE(success); + ASSERT_TRUE(ret.isOk()); + // Wait for listener called after registration, shouldn't timeout + std::unique_lock<std::mutex> lock(mMutex); + EXPECT_NE(mCondition.wait_for(lock, 1s), std::cv_status::timeout); +} + +void IThermalServiceTest::TearDown() { + bool success = false; + binder::Status ret = mThermalSvc->unregisterThermalStatusListener(this, &success); + ASSERT_TRUE(success); + ASSERT_TRUE(ret.isOk()); +} + +class IThermalListenerTest : public IThermalServiceTest, public testing::WithParamInterface<int32_t> { + public: + static auto PrintParam(const testing::TestParamInfo<ParamType> &info) { + return std::to_string(info.param); + } +}; + +TEST_P(IThermalListenerTest, TestListener) { + int level = GetParam(); + std::unique_lock<std::mutex> lock(mMutex); + // Set the override thermal status + setThermalOverride(level); + // Wait for listener called, shouldn't timeout + EXPECT_NE(mCondition.wait_for(lock, 1s), std::cv_status::timeout); + // Check the result + EXPECT_EQ(level, mListenerStatus); + ALOGI("Thermal listener status %d, expecting %d", mListenerStatus, level); +} + +INSTANTIATE_TEST_SUITE_P(TestListenerLevels, IThermalListenerTest, testing::Range( + static_cast<int>(ThermalStatus::THERMAL_STATUS_LIGHT), + static_cast<int>(ThermalStatus::THERMAL_STATUS_SHUTDOWN)), + IThermalListenerTest::PrintParam); + +class IThermalLevelTest : public IThermalServiceTest, public testing::WithParamInterface<int32_t> { + public: + static auto PrintParam(const testing::TestParamInfo<ParamType> &info) { + return std::to_string(info.param); + } +}; + +TEST_P(IThermalLevelTest, TestGetStatusLevel) { + int level = GetParam(); + setThermalOverride(level); + mServiceStatus = getStatusFromService(); + EXPECT_EQ(level, mServiceStatus); +} + +INSTANTIATE_TEST_SUITE_P(TestStatusLevels, IThermalLevelTest, testing::Range( + static_cast<int>(ThermalStatus::THERMAL_STATUS_NONE), + static_cast<int>(ThermalStatus::THERMAL_STATUS_SHUTDOWN)), + IThermalLevelTest::PrintParam); + +int main(int argc, char **argv) { + std::unique_ptr<std::thread> binderLoop; + binderLoop = std::make_unique<std::thread>( + [&] { IPCThreadState::self()->joinThreadPool(true); }); + + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGV("Test result = %d\n", status); + + return status; +}
\ No newline at end of file diff --git a/services/powermanager/Temperature.cpp b/services/powermanager/Temperature.cpp new file mode 100644 index 0000000000..8ec0a87146 --- /dev/null +++ b/services/powermanager/Temperature.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 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 "Temperature" + +#include <android/Temperature.h> +#include <binder/Parcel.h> +#include <utils/Log.h> + +namespace android { +namespace os { + +status_t Temperature::readFromParcel(const android::Parcel *parcel) { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __FUNCTION__); + return BAD_VALUE; + } + + parcel->readFloat(&mValue); + parcel->readInt32(&mType); + parcel->readString16(&mName); + parcel->readInt32(&mStatus); + + return OK; +} + +status_t Temperature::writeToParcel(android::Parcel *parcel) const { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __FUNCTION__); + return BAD_VALUE; + } + + parcel->writeFloat(mValue); + parcel->writeInt32(mType); + parcel->writeString16(mName); + parcel->writeInt32(mStatus); + + return OK; +} + +} // namespace os +} // namespace android
\ No newline at end of file |