diff options
-rw-r--r-- | Android.bp | 12 | ||||
-rw-r--r-- | core/java/android/os/CoolingDevice.aidl | 2 | ||||
-rw-r--r-- | core/java/android/os/IThermalService.aidl | 9 | ||||
-rw-r--r-- | core/java/android/os/Temperature.aidl | 2 | ||||
-rw-r--r-- | native/android/Android.bp | 2 | ||||
-rw-r--r-- | native/android/libandroid.map.txt | 5 | ||||
-rw-r--r-- | native/android/thermal.cpp | 261 | ||||
-rw-r--r-- | services/core/java/com/android/server/power/ThermalManagerService.java | 31 | ||||
-rw-r--r-- | services/core/java/com/android/server/stats/pull/StatsPullAtomService.java | 4 | ||||
-rw-r--r-- | services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java | 21 |
10 files changed, 320 insertions, 29 deletions
diff --git a/Android.bp b/Android.bp index 2534140835f8..df716012b962 100644 --- a/Android.bp +++ b/Android.bp @@ -453,6 +453,18 @@ filegroup { path: "core/java", } +filegroup { + name: "libpowermanager_aidl", + srcs: [ + "core/java/android/os/Temperature.aidl", + "core/java/android/os/CoolingDevice.aidl", + "core/java/android/os/IThermalEventListener.aidl", + "core/java/android/os/IThermalStatusListener.aidl", + "core/java/android/os/IThermalService.aidl", + ], + path: "core/java", +} + java_library { name: "framework-minus-apex", defaults: ["framework-defaults"], diff --git a/core/java/android/os/CoolingDevice.aidl b/core/java/android/os/CoolingDevice.aidl index 478e4bd71e6d..c6432fd31d20 100644 --- a/core/java/android/os/CoolingDevice.aidl +++ b/core/java/android/os/CoolingDevice.aidl @@ -16,4 +16,4 @@ package android.os; -parcelable CoolingDevice; +parcelable CoolingDevice cpp_header "android/CoolingDevice.h"; diff --git a/core/java/android/os/IThermalService.aidl b/core/java/android/os/IThermalService.aidl index ad002335a010..c6c8adc4d8a9 100644 --- a/core/java/android/os/IThermalService.aidl +++ b/core/java/android/os/IThermalService.aidl @@ -56,7 +56,7 @@ interface IThermalService { * @return list of {@link android.os.Temperature}. * {@hide} */ - List<Temperature> getCurrentTemperatures(); + Temperature[] getCurrentTemperatures(); /** * Get current temperature with its throttling status on given temperature type. @@ -64,7 +64,7 @@ interface IThermalService { * @return list of {@link android.os.Temperature}. * {@hide} */ - List<Temperature> getCurrentTemperaturesWithType(in int type); + Temperature[] getCurrentTemperaturesWithType(in int type); /** * Register a listener for thermal status change. @@ -94,7 +94,7 @@ interface IThermalService { * @return list of {@link android.os.CoolingDevice}. * {@hide} */ - List<CoolingDevice> getCurrentCoolingDevices(); + CoolingDevice[] getCurrentCoolingDevices(); /** * Get current cooling devices on given type. @@ -102,7 +102,8 @@ interface IThermalService { * @return list of {@link android.os.CoolingDevice}. * {@hide} */ - List<CoolingDevice> getCurrentCoolingDevicesWithType(in int type); + + CoolingDevice[] getCurrentCoolingDevicesWithType(in int type); /** * @param forecastSeconds how many seconds ahead to forecast the provided headroom diff --git a/core/java/android/os/Temperature.aidl b/core/java/android/os/Temperature.aidl index 708c08fbe8b0..5268dd5441e3 100644 --- a/core/java/android/os/Temperature.aidl +++ b/core/java/android/os/Temperature.aidl @@ -16,4 +16,4 @@ package android.os; -parcelable Temperature; +parcelable Temperature cpp_header "android/Temperature.h"; diff --git a/native/android/Android.bp b/native/android/Android.bp index 257ae7332cc1..640861bcc391 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -51,6 +51,7 @@ cc_library_shared { "surface_control.cpp", "system_fonts.cpp", "trace.cpp", + "thermal.cpp" ], shared_libs: [ @@ -72,6 +73,7 @@ cc_library_shared { "libxml2", "libEGL", "libGLESv2", + "libpowermanager", "android.hardware.configstore@1.0", "android.hardware.configstore-utils", ], diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index a8f1d2c7bbba..d56aa86ae6fa 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -280,6 +280,11 @@ LIBANDROID { android_res_nquery; # introduced=29 android_res_nresult; # introduced=29 android_res_nsend; # introduced=29 + AThermal_acquireManager; # introduced=30 + AThermal_releaseManager; # introduced=30 + AThermal_getCurrentThermalStatus; # introduced=30 + AThermal_registerThermalStatusListener; # introduced=30 + AThermal_unregisterThermalStatusListener; # introduced=30 local: *; }; diff --git a/native/android/thermal.cpp b/native/android/thermal.cpp new file mode 100644 index 000000000000..545c423908a0 --- /dev/null +++ b/native/android/thermal.cpp @@ -0,0 +1,261 @@ +/* + * 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 "thermal" + +#include <cerrno> +#include <thread> + +#include <android/thermal.h> +#include <android/os/BnThermalStatusListener.h> +#include <android/os/IThermalService.h> +#include <binder/IServiceManager.h> +#include <utils/Log.h> + +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; +}; + +struct ListenerCallback { + AThermal_StatusCallback callback; + void* data; +}; + +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); + private: + AThermalManager(sp<IThermalService> service); + sp<IThermalService> mThermalSvc; + sp<ThermalServiceListener> mServiceListener; + std::vector<ListenerCallback> mListeners; + std::mutex mMutex; +}; + +binder::Status ThermalServiceListener::onStatusChange(int32_t status) { + if (mMgr != nullptr) { + mMgr->notifyStateChange(status); + } + return binder::Status::ok(); +} + +AThermalManager* AThermalManager::createAThermalManager() { + sp<IBinder> binder = + defaultServiceManager()->checkService(String16("thermalservice")); + + if (binder == nullptr) { + ALOGE("%s: Thermal service is not ready ", __FUNCTION__); + return nullptr; + } + return new AThermalManager(interface_cast<IThermalService>(binder)); +} + +AThermalManager::AThermalManager(sp<IThermalService> service) + : mThermalSvc(service), + mServiceListener(nullptr) { +} + +AThermalManager::~AThermalManager() { + std::unique_lock<std::mutex> lock(mMutex); + + mListeners.clear(); + if (mServiceListener != nullptr) { + bool success = false; + mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success); + mServiceListener = nullptr; + } +} + +status_t AThermalManager::notifyStateChange(int32_t status) { + std::unique_lock<std::mutex> lock(mMutex); + AThermalStatus thermalStatus = static_cast<AThermalStatus>(status); + + for (auto listener : mListeners) { + listener.callback(listener.data, thermalStatus); + } + return OK; +} + +status_t AThermalManager::addListener(AThermal_StatusCallback callback, void *data) { + std::unique_lock<std::mutex> lock(mMutex); + + if (callback == nullptr) { + // Callback can not be nullptr + return EINVAL; + } + for (const auto& cb : mListeners) { + // Don't re-add callbacks. + if (callback == cb.callback && data == cb.data) { + return EINVAL; + } + } + mListeners.emplace_back(ListenerCallback{callback, data}); + + if (mServiceListener != nullptr) { + return OK; + } + bool success = false; + mServiceListener = new ThermalServiceListener(this); + if (mServiceListener == nullptr) { + return ENOMEM; + } + auto ret = mThermalSvc->registerThermalStatusListener(mServiceListener, &success); + if (!success || !ret.isOk()) { + ALOGE("Failed in registerThermalStatusListener %d", success); + if (ret.exceptionCode() == binder::Status::EX_SECURITY) { + return EPERM; + } + return EPIPE; + } + return OK; +} + +status_t AThermalManager::removeListener(AThermal_StatusCallback callback, void *data) { + std::unique_lock<std::mutex> lock(mMutex); + + auto it = std::remove_if(mListeners.begin(), + mListeners.end(), + [&](const ListenerCallback& cb) { + return callback == cb.callback && + data == cb.data; + }); + if (it == mListeners.end()) { + // If the listener and data pointer were not previously added. + return EINVAL; + } + mListeners.erase(it, mListeners.end()); + + if (!mListeners.empty()) { + return OK; + } + if (mServiceListener == nullptr) { + return OK; + } + bool success = false; + auto ret = mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success); + if (!success || !ret.isOk()) { + ALOGE("Failed in unregisterThermalStatusListener %d", success); + if (ret.exceptionCode() == binder::Status::EX_SECURITY) { + return EPERM; + } + return EPIPE; + } + mServiceListener = nullptr; + return OK; +} + +status_t AThermalManager::getCurrentThermalStatus(int32_t *status) { + binder::Status ret = mThermalSvc->getCurrentThermalStatus(status); + + if (!ret.isOk()) { + if (ret.exceptionCode() == binder::Status::EX_SECURITY) { + return EPERM; + } + return EPIPE; + } + 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); + if (ret != OK) { + return AThermalStatus::ATHERMAL_STATUS_ERROR; + } + 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); +} + +/** + * 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); +} diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java index da3cbf9d03b4..74c3a9ec375b 100644 --- a/services/core/java/com/android/server/power/ThermalManagerService.java +++ b/services/core/java/com/android/server/power/ThermalManagerService.java @@ -370,30 +370,33 @@ public class ThermalManagerService extends SystemService { } @Override - public List<Temperature> getCurrentTemperatures() { + public Temperature[] getCurrentTemperatures() { getContext().enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null); final long token = Binder.clearCallingIdentity(); try { if (!mHalReady.get()) { - return new ArrayList<>(); + return new Temperature[0]; } - return mHalWrapper.getCurrentTemperatures(false, 0 /* not used */); + final List<Temperature> curr = mHalWrapper.getCurrentTemperatures( + false, 0 /* not used */); + return curr.toArray(new Temperature[curr.size()]); } finally { Binder.restoreCallingIdentity(token); } } @Override - public List<Temperature> getCurrentTemperaturesWithType(int type) { + public Temperature[] getCurrentTemperaturesWithType(int type) { getContext().enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null); final long token = Binder.clearCallingIdentity(); try { if (!mHalReady.get()) { - return new ArrayList<>(); + return new Temperature[0]; } - return mHalWrapper.getCurrentTemperatures(true, type); + final List<Temperature> curr = mHalWrapper.getCurrentTemperatures(true, type); + return curr.toArray(new Temperature[curr.size()]); } finally { Binder.restoreCallingIdentity(token); } @@ -443,30 +446,34 @@ public class ThermalManagerService extends SystemService { } @Override - public List<CoolingDevice> getCurrentCoolingDevices() { + public CoolingDevice[] getCurrentCoolingDevices() { getContext().enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null); final long token = Binder.clearCallingIdentity(); try { if (!mHalReady.get()) { - return new ArrayList<>(); + return new CoolingDevice[0]; } - return mHalWrapper.getCurrentCoolingDevices(false, 0); + final List<CoolingDevice> devList = mHalWrapper.getCurrentCoolingDevices( + false, 0); + return devList.toArray(new CoolingDevice[devList.size()]); } finally { Binder.restoreCallingIdentity(token); } } @Override - public List<CoolingDevice> getCurrentCoolingDevicesWithType(int type) { + public CoolingDevice[] getCurrentCoolingDevicesWithType(int type) { getContext().enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null); final long token = Binder.clearCallingIdentity(); try { if (!mHalReady.get()) { - return new ArrayList<>(); + return new CoolingDevice[0]; } - return mHalWrapper.getCurrentCoolingDevices(true, type); + final List<CoolingDevice> devList = mHalWrapper.getCurrentCoolingDevices( + true, type); + return devList.toArray(new CoolingDevice[devList.size()]); } finally { Binder.restoreCallingIdentity(token); } diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 47a26f576949..2b111f7fbc12 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -1515,7 +1515,7 @@ public class StatsPullAtomService extends SystemService { } final long callingToken = Binder.clearCallingIdentity(); try { - List<Temperature> temperatures = thermalService.getCurrentTemperatures(); + Temperature temperatures[] = thermalService.getCurrentTemperatures(); for (Temperature temp : temperatures) { StatsEvent e = StatsEvent.newBuilder() .setAtomId(atomTag) @@ -1553,7 +1553,7 @@ public class StatsPullAtomService extends SystemService { } final long callingToken = Binder.clearCallingIdentity(); try { - List<CoolingDevice> devices = thermalService.getCurrentCoolingDevices(); + CoolingDevice devices[] = thermalService.getCurrentCoolingDevices(); for (CoolingDevice device : devices) { StatsEvent e = StatsEvent.newBuilder() .setAtomId(atomTag) diff --git a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java index 624cb83f9e19..9e067304fc7f 100644 --- a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java @@ -297,9 +297,11 @@ public class ThermalManagerServiceTest { @Test public void testGetCurrentTemperatures() throws RemoteException { assertListEqualsIgnoringOrder(mFakeHal.getCurrentTemperatures(false, 0), - mService.mService.getCurrentTemperatures()); - assertListEqualsIgnoringOrder(mFakeHal.getCurrentTemperatures(true, Temperature.TYPE_SKIN), - mService.mService.getCurrentTemperaturesWithType(Temperature.TYPE_SKIN)); + Arrays.asList(mService.mService.getCurrentTemperatures())); + assertListEqualsIgnoringOrder( + mFakeHal.getCurrentTemperatures(true, Temperature.TYPE_SKIN), + Arrays.asList(mService.mService.getCurrentTemperaturesWithType( + Temperature.TYPE_SKIN))); } @Test @@ -331,21 +333,22 @@ public class ThermalManagerServiceTest { assertTrue(mService.mService.registerThermalStatusListener(mStatusListener1)); assertTrue(mService.mService.unregisterThermalEventListener(mEventListener1)); assertTrue(mService.mService.unregisterThermalStatusListener(mStatusListener1)); - assertEquals(0, mService.mService.getCurrentTemperatures().size()); - assertEquals(0, - mService.mService.getCurrentTemperaturesWithType(Temperature.TYPE_SKIN).size()); + assertEquals(0, Arrays.asList(mService.mService.getCurrentTemperatures()).size()); + assertEquals(0, Arrays.asList(mService.mService.getCurrentTemperaturesWithType( + Temperature.TYPE_SKIN)).size()); assertEquals(Temperature.THROTTLING_NONE, mService.mService.getCurrentThermalStatus()); } @Test public void testGetCurrentCoolingDevices() throws RemoteException { assertListEqualsIgnoringOrder(mFakeHal.getCurrentCoolingDevices(false, 0), - mService.mService.getCurrentCoolingDevices()); + Arrays.asList(mService.mService.getCurrentCoolingDevices())); assertListEqualsIgnoringOrder( mFakeHal.getCurrentCoolingDevices(false, CoolingDevice.TYPE_BATTERY), - mService.mService.getCurrentCoolingDevices()); + Arrays.asList(mService.mService.getCurrentCoolingDevices())); assertListEqualsIgnoringOrder( mFakeHal.getCurrentCoolingDevices(true, CoolingDevice.TYPE_CPU), - mService.mService.getCurrentCoolingDevicesWithType(CoolingDevice.TYPE_CPU)); + Arrays.asList(mService.mService.getCurrentCoolingDevicesWithType( + CoolingDevice.TYPE_CPU))); } } |