diff options
author | 2024-02-07 23:39:50 +0000 | |
---|---|---|
committer | 2024-03-04 22:08:15 +0000 | |
commit | 6c18e6da2aa9758eb7c9a639f44a15a45723f65b (patch) | |
tree | fe12dce50bca48dd2f28bb616ffc3fad03253406 | |
parent | 415c59e4430e8aa34295cf09d6c0eb7ee5658705 (diff) |
Update PowerHAL wrapper support checking behavior
- Updates support checks to check status for UNKNOWN_TRANSACTION
- Adds PowerHintSessionWrapper class to check support on session methods
- Ensures that wrapper methods check the HAL version number for support
- Adds macros to cache returned wrapper call support status
Bug: 324255931
Test: atest libpowermanager_test
Test: atest libsurfaceflinger_unittest:PowerAdvisorTest
Change-Id: I4b329e6b55c53198bb064a34e792be6336e66e27
21 files changed, 669 insertions, 294 deletions
diff --git a/include/powermanager/HalResult.h b/include/powermanager/HalResult.h new file mode 100644 index 0000000000..7fe3822be0 --- /dev/null +++ b/include/powermanager/HalResult.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2024 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. + */ + +#pragma once + +#include <android/binder_auto_utils.h> +#include <android/binder_status.h> +#include <android/hardware/power/1.0/IPower.h> +#include <binder/Status.h> +#include <hidl/HidlSupport.h> +#include <string> + +namespace android::power { + +static bool checkUnsupported(const ndk::ScopedAStatus& ndkStatus) { + return ndkStatus.getExceptionCode() == EX_UNSUPPORTED_OPERATION || + ndkStatus.getStatus() == STATUS_UNKNOWN_TRANSACTION; +} + +static bool checkUnsupported(const binder::Status& status) { + return status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION || + status.transactionError() == UNKNOWN_TRANSACTION; +} + +// Result of a call to the Power HAL wrapper, holding data if successful. +template <typename T> +class HalResult { +public: + static HalResult<T> ok(T&& value) { return HalResult(std::forward<T>(value)); } + static HalResult<T> ok(T& value) { return HalResult<T>::ok(T{value}); } + static HalResult<T> failed(std::string msg) { return HalResult(msg, /* unsupported= */ false); } + static HalResult<T> unsupported() { return HalResult("", /* unsupported= */ true); } + + static HalResult<T> fromStatus(const binder::Status& status, T&& data) { + if (checkUnsupported(status)) { + return HalResult<T>::unsupported(); + } + if (status.isOk()) { + return HalResult<T>::ok(std::forward<T>(data)); + } + return HalResult<T>::failed(std::string(status.toString8().c_str())); + } + + static HalResult<T> fromStatus(const binder::Status& status, T& data) { + return HalResult<T>::fromStatus(status, T{data}); + } + + static HalResult<T> fromStatus(const ndk::ScopedAStatus& ndkStatus, T&& data) { + if (checkUnsupported(ndkStatus)) { + return HalResult<T>::unsupported(); + } + if (ndkStatus.isOk()) { + return HalResult<T>::ok(std::forward<T>(data)); + } + return HalResult<T>::failed(std::string(ndkStatus.getDescription())); + } + + static HalResult<T> fromStatus(const ndk::ScopedAStatus& ndkStatus, T& data) { + return HalResult<T>::fromStatus(ndkStatus, T{data}); + } + + template <typename R> + static HalResult<T> fromReturn(hardware::Return<R>& ret, T&& data) { + return ret.isOk() ? HalResult<T>::ok(std::forward<T>(data)) + : HalResult<T>::failed(ret.description()); + } + + template <typename R> + static HalResult<T> fromReturn(hardware::Return<R>& ret, T& data) { + return HalResult<T>::fromReturn(ret, T{data}); + } + + template <typename R> + static HalResult<T> fromReturn(hardware::Return<R>& ret, hardware::power::V1_0::Status status, + T&& data) { + return ret.isOk() ? HalResult<T>::fromStatus(status, std::forward<T>(data)) + : HalResult<T>::failed(ret.description()); + } + + template <typename R> + static HalResult<T> fromReturn(hardware::Return<R>& ret, hardware::power::V1_0::Status status, + T& data) { + return HalResult<T>::fromReturn(ret, status, T{data}); + } + + // This will throw std::bad_optional_access if this result is not ok. + const T& value() const { return mValue.value(); } + bool isOk() const { return !mUnsupported && mValue.has_value(); } + bool isFailed() const { return !mUnsupported && !mValue.has_value(); } + bool isUnsupported() const { return mUnsupported; } + const char* errorMessage() const { return mErrorMessage.c_str(); } + +private: + std::optional<T> mValue; + std::string mErrorMessage; + bool mUnsupported; + + explicit HalResult(T&& value) + : mValue{std::move(value)}, mErrorMessage(), mUnsupported(false) {} + explicit HalResult(std::string errorMessage, bool unsupported) + : mValue(), mErrorMessage(std::move(errorMessage)), mUnsupported(unsupported) {} +}; + +// Empty result +template <> +class HalResult<void> { +public: + static HalResult<void> ok() { return HalResult(); } + static HalResult<void> failed(std::string msg) { return HalResult(std::move(msg)); } + static HalResult<void> unsupported() { return HalResult(/* unsupported= */ true); } + + static HalResult<void> fromStatus(const binder::Status& status) { + if (checkUnsupported(status)) { + return HalResult<void>::unsupported(); + } + if (status.isOk()) { + return HalResult<void>::ok(); + } + return HalResult<void>::failed(std::string(status.toString8().c_str())); + } + + static HalResult<void> fromStatus(const ndk::ScopedAStatus& ndkStatus) { + if (ndkStatus.isOk()) { + return HalResult<void>::ok(); + } + if (checkUnsupported(ndkStatus)) { + return HalResult<void>::unsupported(); + } + return HalResult<void>::failed(ndkStatus.getDescription()); + } + + template <typename R> + static HalResult<void> fromReturn(hardware::Return<R>& ret) { + return ret.isOk() ? HalResult<void>::ok() : HalResult<void>::failed(ret.description()); + } + + bool isOk() const { return !mUnsupported && !mFailed; } + bool isFailed() const { return !mUnsupported && mFailed; } + bool isUnsupported() const { return mUnsupported; } + const char* errorMessage() const { return mErrorMessage.c_str(); } + +private: + std::string mErrorMessage; + bool mFailed; + bool mUnsupported; + + explicit HalResult(bool unsupported = false) + : mErrorMessage(), mFailed(false), mUnsupported(unsupported) {} + explicit HalResult(std::string errorMessage) + : mErrorMessage(std::move(errorMessage)), mFailed(true), mUnsupported(false) {} +}; +} // namespace android::power diff --git a/include/powermanager/PowerHalController.h b/include/powermanager/PowerHalController.h index c50bc4a188..7e0bd5bedc 100644 --- a/include/powermanager/PowerHalController.h +++ b/include/powermanager/PowerHalController.h @@ -23,6 +23,7 @@ #include <aidl/android/hardware/power/Mode.h> #include <android-base/thread_annotations.h> #include <powermanager/PowerHalWrapper.h> +#include <powermanager/PowerHintSessionWrapper.h> namespace android { @@ -38,6 +39,7 @@ public: virtual std::unique_ptr<HalWrapper> connect(); virtual void reset(); + virtual int32_t getAidlVersion(); }; // ------------------------------------------------------------------------------------------------- @@ -59,14 +61,13 @@ public: int32_t durationMs) override; virtual HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) override; - virtual HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> - createHintSession(int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, - int64_t durationNanos) override; - virtual HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> - createHintSessionWithConfig(int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, - int64_t durationNanos, - aidl::android::hardware::power::SessionTag tag, - aidl::android::hardware::power::SessionConfig* config) override; + virtual HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSession( + int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, + int64_t durationNanos) override; + virtual HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSessionWithConfig( + int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos, + aidl::android::hardware::power::SessionTag tag, + aidl::android::hardware::power::SessionConfig* config) override; virtual HalResult<int64_t> getHintSessionPreferredRate() override; virtual HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel( int tgid, int uid) override; diff --git a/include/powermanager/PowerHalLoader.h b/include/powermanager/PowerHalLoader.h index cbbfa597ba..ab66336738 100644 --- a/include/powermanager/PowerHalLoader.h +++ b/include/powermanager/PowerHalLoader.h @@ -36,6 +36,8 @@ public: static sp<hardware::power::V1_1::IPower> loadHidlV1_1(); static sp<hardware::power::V1_2::IPower> loadHidlV1_2(); static sp<hardware::power::V1_3::IPower> loadHidlV1_3(); + // Returns aidl interface version, or 0 if AIDL is not used + static int32_t getAidlVersion(); private: static std::mutex gHalMutex; @@ -48,6 +50,8 @@ private: static sp<hardware::power::V1_0::IPower> loadHidlV1_0Locked() EXCLUSIVE_LOCKS_REQUIRED(gHalMutex); + static int32_t gAidlInterfaceVersion; + PowerHalLoader() = delete; ~PowerHalLoader() = delete; }; diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h index e2da014606..6e347a9ce9 100644 --- a/include/powermanager/PowerHalWrapper.h +++ b/include/powermanager/PowerHalWrapper.h @@ -26,6 +26,9 @@ #include <android/hardware/power/1.1/IPower.h> #include <android/hardware/power/1.2/IPower.h> #include <android/hardware/power/1.3/IPower.h> +#include <powermanager/HalResult.h> +#include <powermanager/PowerHintSessionWrapper.h> + #include <binder/Status.h> #include <utility> @@ -41,134 +44,6 @@ enum class HalSupport { OFF = 2, }; -// Result of a call to the Power HAL wrapper, holding data if successful. -template <typename T> -class HalResult { -public: - static HalResult<T> ok(T&& value) { return HalResult(std::forward<T>(value)); } - static HalResult<T> ok(T& value) { return HalResult<T>::ok(T{value}); } - static HalResult<T> failed(std::string msg) { return HalResult(msg, /* unsupported= */ false); } - static HalResult<T> unsupported() { return HalResult("", /* unsupported= */ true); } - - static HalResult<T> fromStatus(const binder::Status& status, T&& data) { - if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { - return HalResult<T>::unsupported(); - } - if (status.isOk()) { - return HalResult<T>::ok(std::forward<T>(data)); - } - return HalResult<T>::failed(std::string(status.toString8().c_str())); - } - - static HalResult<T> fromStatus(const binder::Status& status, T& data) { - return HalResult<T>::fromStatus(status, T{data}); - } - - static HalResult<T> fromStatus(const ndk::ScopedAStatus& status, T&& data) { - if (status.getExceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { - return HalResult<T>::unsupported(); - } - if (status.isOk()) { - return HalResult<T>::ok(std::forward<T>(data)); - } - return HalResult<T>::failed(std::string(status.getDescription())); - } - - static HalResult<T> fromStatus(const ndk::ScopedAStatus& status, T& data) { - return HalResult<T>::fromStatus(status, T{data}); - } - - template <typename R> - static HalResult<T> fromReturn(hardware::Return<R>& ret, T&& data) { - return ret.isOk() ? HalResult<T>::ok(std::forward<T>(data)) - : HalResult<T>::failed(ret.description()); - } - - template <typename R> - static HalResult<T> fromReturn(hardware::Return<R>& ret, T& data) { - return HalResult<T>::fromReturn(ret, T{data}); - } - - template <typename R> - static HalResult<T> fromReturn(hardware::Return<R>& ret, hardware::power::V1_0::Status status, - T&& data) { - return ret.isOk() ? HalResult<T>::fromStatus(status, std::forward<T>(data)) - : HalResult<T>::failed(ret.description()); - } - - template <typename R> - static HalResult<T> fromReturn(hardware::Return<R>& ret, hardware::power::V1_0::Status status, - T& data) { - return HalResult<T>::fromReturn(ret, status, T{data}); - } - - // This will throw std::bad_optional_access if this result is not ok. - const T& value() const { return mValue.value(); } - bool isOk() const { return !mUnsupported && mValue.has_value(); } - bool isFailed() const { return !mUnsupported && !mValue.has_value(); } - bool isUnsupported() const { return mUnsupported; } - const char* errorMessage() const { return mErrorMessage.c_str(); } - -private: - std::optional<T> mValue; - std::string mErrorMessage; - bool mUnsupported; - - explicit HalResult(T&& value) - : mValue{std::move(value)}, mErrorMessage(), mUnsupported(false) {} - explicit HalResult(std::string errorMessage, bool unsupported) - : mValue(), mErrorMessage(std::move(errorMessage)), mUnsupported(unsupported) {} -}; - -// Empty result of a call to the Power HAL wrapper. -template <> -class HalResult<void> { -public: - static HalResult<void> ok() { return HalResult(); } - static HalResult<void> failed(std::string msg) { return HalResult(std::move(msg)); } - static HalResult<void> unsupported() { return HalResult(/* unsupported= */ true); } - - static HalResult<void> fromStatus(const binder::Status& status) { - if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { - return HalResult<void>::unsupported(); - } - if (status.isOk()) { - return HalResult<void>::ok(); - } - return HalResult<void>::failed(std::string(status.toString8().c_str())); - } - - static HalResult<void> fromStatus(const ndk::ScopedAStatus& status) { - if (status.getExceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { - return HalResult<void>::unsupported(); - } - if (status.isOk()) { - return HalResult<void>::ok(); - } - return HalResult<void>::failed(std::string(status.getDescription())); - } - - template <typename R> - static HalResult<void> fromReturn(hardware::Return<R>& ret) { - return ret.isOk() ? HalResult<void>::ok() : HalResult<void>::failed(ret.description()); - } - - bool isOk() const { return !mUnsupported && !mFailed; } - bool isFailed() const { return !mUnsupported && mFailed; } - bool isUnsupported() const { return mUnsupported; } - const char* errorMessage() const { return mErrorMessage.c_str(); } - -private: - std::string mErrorMessage; - bool mFailed; - bool mUnsupported; - - explicit HalResult(bool unsupported = false) - : mErrorMessage(), mFailed(false), mUnsupported(unsupported) {} - explicit HalResult(std::string errorMessage) - : mErrorMessage(std::move(errorMessage)), mFailed(true), mUnsupported(false) {} -}; - // Wrapper for Power HAL handlers. class HalWrapper { public: @@ -177,14 +52,13 @@ public: virtual HalResult<void> setBoost(aidl::android::hardware::power::Boost boost, int32_t durationMs) = 0; virtual HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) = 0; - virtual HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> - createHintSession(int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, - int64_t durationNanos) = 0; - virtual HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> - createHintSessionWithConfig(int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, - int64_t durationNanos, - aidl::android::hardware::power::SessionTag tag, - aidl::android::hardware::power::SessionConfig* config) = 0; + virtual HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSession( + int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, + int64_t durationNanos) = 0; + virtual HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSessionWithConfig( + int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos, + aidl::android::hardware::power::SessionTag tag, + aidl::android::hardware::power::SessionConfig* config) = 0; virtual HalResult<int64_t> getHintSessionPreferredRate() = 0; virtual HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(int tgid, int uid) = 0; @@ -200,14 +74,13 @@ public: HalResult<void> setBoost(aidl::android::hardware::power::Boost boost, int32_t durationMs) override; HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) override; - HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> createHintSession( + HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSession( int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos) override; - HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> - createHintSessionWithConfig(int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, - int64_t durationNanos, - aidl::android::hardware::power::SessionTag tag, - aidl::android::hardware::power::SessionConfig* config) override; + HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSessionWithConfig( + int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos, + aidl::android::hardware::power::SessionTag tag, + aidl::android::hardware::power::SessionConfig* config) override; HalResult<int64_t> getHintSessionPreferredRate() override; HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(int tgid, int uid) override; @@ -285,14 +158,13 @@ public: HalResult<void> setBoost(aidl::android::hardware::power::Boost boost, int32_t durationMs) override; HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) override; - HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> createHintSession( + HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSession( int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos) override; - HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> - createHintSessionWithConfig(int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, - int64_t durationNanos, - aidl::android::hardware::power::SessionTag tag, - aidl::android::hardware::power::SessionConfig* config) override; + HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSessionWithConfig( + int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos, + aidl::android::hardware::power::SessionTag tag, + aidl::android::hardware::power::SessionConfig* config) override; HalResult<int64_t> getHintSessionPreferredRate() override; HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(int tgid, @@ -307,14 +179,12 @@ private: std::mutex mBoostMutex; std::mutex mModeMutex; std::shared_ptr<aidl::android::hardware::power::IPower> mHandle; - // Android framework only sends boost upto DISPLAY_UPDATE_IMMINENT. - // Need to increase the array size if more boost supported. - std::array< - std::atomic<HalSupport>, - static_cast<int32_t>(aidl::android::hardware::power::Boost::DISPLAY_UPDATE_IMMINENT) + - 1> + std::array<HalSupport, + static_cast<int32_t>( + *(ndk::enum_range<aidl::android::hardware::power::Boost>().end() - 1)) + + 1> mBoostSupportedArray GUARDED_BY(mBoostMutex) = {HalSupport::UNKNOWN}; - std::array<std::atomic<HalSupport>, + std::array<HalSupport, static_cast<int32_t>( *(ndk::enum_range<aidl::android::hardware::power::Mode>().end() - 1)) + 1> diff --git a/include/powermanager/PowerHintSessionWrapper.h b/include/powermanager/PowerHintSessionWrapper.h new file mode 100644 index 0000000000..ba6fe77c80 --- /dev/null +++ b/include/powermanager/PowerHintSessionWrapper.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 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. + */ + +#pragma once + +#include <aidl/android/hardware/power/Boost.h> +#include <aidl/android/hardware/power/ChannelConfig.h> +#include <aidl/android/hardware/power/IPower.h> +#include <aidl/android/hardware/power/IPowerHintSession.h> +#include <aidl/android/hardware/power/Mode.h> +#include <aidl/android/hardware/power/SessionConfig.h> +#include <android-base/thread_annotations.h> +#include "HalResult.h" + +namespace android::power { + +// Wrapper for power hint sessions, which allows for better mocking, +// support checking, and failure handling than using hint sessions directly +class PowerHintSessionWrapper { +public: + virtual ~PowerHintSessionWrapper() = default; + PowerHintSessionWrapper( + std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>&& session); + virtual HalResult<void> updateTargetWorkDuration(int64_t in_targetDurationNanos); + virtual HalResult<void> reportActualWorkDuration( + const std::vector<::aidl::android::hardware::power::WorkDuration>& in_durations); + virtual HalResult<void> pause(); + virtual HalResult<void> resume(); + virtual HalResult<void> close(); + virtual HalResult<void> sendHint(::aidl::android::hardware::power::SessionHint in_hint); + virtual HalResult<void> setThreads(const std::vector<int32_t>& in_threadIds); + virtual HalResult<void> setMode(::aidl::android::hardware::power::SessionMode in_type, + bool in_enabled); + virtual HalResult<aidl::android::hardware::power::SessionConfig> getSessionConfig(); + +private: + std::shared_ptr<aidl::android::hardware::power::IPowerHintSession> mSession; + int32_t mInterfaceVersion; +}; + +} // namespace android::power
\ No newline at end of file diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp index 1f72e8ba2c..3ea08febfd 100644 --- a/services/powermanager/Android.bp +++ b/services/powermanager/Android.bp @@ -17,6 +17,7 @@ cc_library_shared { "PowerHalController.cpp", "PowerHalLoader.cpp", "PowerHalWrapper.cpp", + "PowerHintSessionWrapper.cpp", "PowerSaveState.cpp", "Temperature.cpp", "WorkDuration.cpp", diff --git a/services/powermanager/PowerHalController.cpp b/services/powermanager/PowerHalController.cpp index bc178bce8f..40fd097491 100644 --- a/services/powermanager/PowerHalController.cpp +++ b/services/powermanager/PowerHalController.cpp @@ -57,6 +57,10 @@ void HalConnector::reset() { PowerHalLoader::unloadAll(); } +int32_t HalConnector::getAidlVersion() { + return PowerHalLoader::getAidlVersion(); +} + // ------------------------------------------------------------------------------------------------- void PowerHalController::init() { @@ -77,6 +81,22 @@ std::shared_ptr<HalWrapper> PowerHalController::initHal() { return mConnectedHal; } +// Using statement expression macro instead of a method lets the static be +// scoped to the outer method while dodging the need for a support lookup table +// This only works for AIDL methods that do not vary supported/unsupported depending +// on their arguments (not setBoost, setMode) which do their own support checks +#define CACHE_SUPPORT(version, method) \ + ({ \ + static bool support = mHalConnector->getAidlVersion() >= version; \ + !support ? decltype(method)::unsupported() : ({ \ + auto result = method; \ + if (result.isUnsupported()) { \ + support = false; \ + } \ + std::move(result); \ + }); \ + }) + // Check if a call to Power HAL function failed; if so, log the failure and // invalidate the current Power HAL handle. template <typename T> @@ -103,40 +123,49 @@ HalResult<void> PowerHalController::setMode(aidl::android::hardware::power::Mode return processHalResult(handle->setMode(mode, enabled), "setMode"); } -HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> -PowerHalController::createHintSession(int32_t tgid, int32_t uid, - const std::vector<int32_t>& threadIds, - int64_t durationNanos) { +// Aidl-only methods + +HalResult<std::shared_ptr<PowerHintSessionWrapper>> PowerHalController::createHintSession( + int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos) { std::shared_ptr<HalWrapper> handle = initHal(); - return processHalResult(handle->createHintSession(tgid, uid, threadIds, durationNanos), - "createHintSession"); + return CACHE_SUPPORT(2, + processHalResult(handle->createHintSession(tgid, uid, threadIds, + durationNanos), + "createHintSession")); } -HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> -PowerHalController::createHintSessionWithConfig( +HalResult<std::shared_ptr<PowerHintSessionWrapper>> PowerHalController::createHintSessionWithConfig( int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos, aidl::android::hardware::power::SessionTag tag, aidl::android::hardware::power::SessionConfig* config) { std::shared_ptr<HalWrapper> handle = initHal(); - return processHalResult(handle->createHintSessionWithConfig(tgid, uid, threadIds, durationNanos, - tag, config), - "createHintSessionWithConfig"); + return CACHE_SUPPORT(5, + processHalResult(handle->createHintSessionWithConfig(tgid, uid, threadIds, + durationNanos, tag, + config), + "createHintSessionWithConfig")); } HalResult<int64_t> PowerHalController::getHintSessionPreferredRate() { std::shared_ptr<HalWrapper> handle = initHal(); - return processHalResult(handle->getHintSessionPreferredRate(), "getHintSessionPreferredRate"); + return CACHE_SUPPORT(2, + processHalResult(handle->getHintSessionPreferredRate(), + "getHintSessionPreferredRate")); } HalResult<aidl::android::hardware::power::ChannelConfig> PowerHalController::getSessionChannel( int tgid, int uid) { std::shared_ptr<HalWrapper> handle = initHal(); - return processHalResult(handle->getSessionChannel(tgid, uid), "getSessionChannel"); + return CACHE_SUPPORT(5, + processHalResult(handle->getSessionChannel(tgid, uid), + "getSessionChannel")); } HalResult<void> PowerHalController::closeSessionChannel(int tgid, int uid) { std::shared_ptr<HalWrapper> handle = initHal(); - return processHalResult(handle->closeSessionChannel(tgid, uid), "closeSessionChannel"); + return CACHE_SUPPORT(5, + processHalResult(handle->closeSessionChannel(tgid, uid), + "closeSessionChannel")); } } // namespace power diff --git a/services/powermanager/PowerHalLoader.cpp b/services/powermanager/PowerHalLoader.cpp index 22144615da..ea284c36d8 100644 --- a/services/powermanager/PowerHalLoader.cpp +++ b/services/powermanager/PowerHalLoader.cpp @@ -60,6 +60,7 @@ sp<V1_0::IPower> PowerHalLoader::gHalHidlV1_0 = nullptr; sp<V1_1::IPower> PowerHalLoader::gHalHidlV1_1 = nullptr; sp<V1_2::IPower> PowerHalLoader::gHalHidlV1_2 = nullptr; sp<V1_3::IPower> PowerHalLoader::gHalHidlV1_3 = nullptr; +int32_t PowerHalLoader::gAidlInterfaceVersion = 0; void PowerHalLoader::unloadAll() { std::lock_guard<std::mutex> lock(gHalMutex); @@ -89,6 +90,8 @@ std::shared_ptr<aidl::android::hardware::power::IPower> PowerHalLoader::loadAidl ndk::SpAIBinder(AServiceManager_waitForService(aidlServiceName.c_str()))); if (gHalAidl) { ALOGI("Successfully connected to Power HAL AIDL service."); + gHalAidl->getInterfaceVersion(&gAidlInterfaceVersion); + } else { ALOGI("Power HAL AIDL service not available."); gHalExists = false; @@ -128,6 +131,10 @@ sp<V1_0::IPower> PowerHalLoader::loadHidlV1_0Locked() { return loadHal<V1_0::IPower>(gHalExists, gHalHidlV1_0, loadFn, "HIDL v1.0"); } +int32_t PowerHalLoader::getAidlVersion() { + return gAidlInterfaceVersion; +} + // ------------------------------------------------------------------------------------------------- } // namespace power diff --git a/services/powermanager/PowerHalWrapper.cpp b/services/powermanager/PowerHalWrapper.cpp index 1009100cc2..bd6685cbad 100644 --- a/services/powermanager/PowerHalWrapper.cpp +++ b/services/powermanager/PowerHalWrapper.cpp @@ -18,11 +18,10 @@ #include <aidl/android/hardware/power/Boost.h> #include <aidl/android/hardware/power/IPowerHintSession.h> #include <aidl/android/hardware/power/Mode.h> +#include <powermanager/HalResult.h> #include <powermanager/PowerHalWrapper.h> #include <utils/Log.h> -#include <cinttypes> - using namespace android::hardware::power; namespace Aidl = aidl::android::hardware::power; @@ -31,15 +30,6 @@ namespace android { namespace power { // ------------------------------------------------------------------------------------------------- -inline HalResult<void> toHalResult(const ndk::ScopedAStatus& result) { - if (result.isOk()) { - return HalResult<void>::ok(); - } - ALOGE("Power HAL request failed: %s", result.getDescription().c_str()); - return HalResult<void>::failed(result.getDescription()); -} - -// ------------------------------------------------------------------------------------------------- HalResult<void> EmptyHalWrapper::setBoost(Aidl::Boost boost, int32_t durationMs) { ALOGV("Skipped setBoost %s with duration %dms because %s", toString(boost).c_str(), durationMs, @@ -53,19 +43,19 @@ HalResult<void> EmptyHalWrapper::setMode(Aidl::Mode mode, bool enabled) { return HalResult<void>::unsupported(); } -HalResult<std::shared_ptr<Aidl::IPowerHintSession>> EmptyHalWrapper::createHintSession( +HalResult<std::shared_ptr<PowerHintSessionWrapper>> EmptyHalWrapper::createHintSession( int32_t, int32_t, const std::vector<int32_t>& threadIds, int64_t) { ALOGV("Skipped createHintSession(task num=%zu) because %s", threadIds.size(), getUnsupportedMessage()); - return HalResult<std::shared_ptr<Aidl::IPowerHintSession>>::unsupported(); + return HalResult<std::shared_ptr<PowerHintSessionWrapper>>::unsupported(); } -HalResult<std::shared_ptr<Aidl::IPowerHintSession>> EmptyHalWrapper::createHintSessionWithConfig( +HalResult<std::shared_ptr<PowerHintSessionWrapper>> EmptyHalWrapper::createHintSessionWithConfig( int32_t, int32_t, const std::vector<int32_t>& threadIds, int64_t, Aidl::SessionTag, Aidl::SessionConfig*) { ALOGV("Skipped createHintSessionWithConfig(task num=%zu) because %s", threadIds.size(), getUnsupportedMessage()); - return HalResult<std::shared_ptr<Aidl::IPowerHintSession>>::unsupported(); + return HalResult<std::shared_ptr<PowerHintSessionWrapper>>::unsupported(); } HalResult<int64_t> EmptyHalWrapper::getHintSessionPreferredRate() { @@ -225,7 +215,7 @@ HalResult<void> AidlHalWrapper::setBoost(Aidl::Boost boost, int32_t durationMs) } lock.unlock(); - return toHalResult(mHandle->setBoost(boost, durationMs)); + return HalResult<void>::fromStatus(mHandle->setBoost(boost, durationMs)); } HalResult<void> AidlHalWrapper::setMode(Aidl::Mode mode, bool enabled) { @@ -253,25 +243,25 @@ HalResult<void> AidlHalWrapper::setMode(Aidl::Mode mode, bool enabled) { } lock.unlock(); - return toHalResult(mHandle->setMode(mode, enabled)); + return HalResult<void>::fromStatus(mHandle->setMode(mode, enabled)); } -HalResult<std::shared_ptr<Aidl::IPowerHintSession>> AidlHalWrapper::createHintSession( +HalResult<std::shared_ptr<PowerHintSessionWrapper>> AidlHalWrapper::createHintSession( int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos) { std::shared_ptr<Aidl::IPowerHintSession> appSession; - return HalResult<std::shared_ptr<Aidl::IPowerHintSession>>:: + return HalResult<std::shared_ptr<PowerHintSessionWrapper>>:: fromStatus(mHandle->createHintSession(tgid, uid, threadIds, durationNanos, &appSession), - std::move(appSession)); + std::make_shared<PowerHintSessionWrapper>(std::move(appSession))); } -HalResult<std::shared_ptr<Aidl::IPowerHintSession>> AidlHalWrapper::createHintSessionWithConfig( +HalResult<std::shared_ptr<PowerHintSessionWrapper>> AidlHalWrapper::createHintSessionWithConfig( int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos, Aidl::SessionTag tag, Aidl::SessionConfig* config) { std::shared_ptr<Aidl::IPowerHintSession> appSession; - return HalResult<std::shared_ptr<Aidl::IPowerHintSession>>:: + return HalResult<std::shared_ptr<PowerHintSessionWrapper>>:: fromStatus(mHandle->createHintSessionWithConfig(tgid, uid, threadIds, durationNanos, tag, config, &appSession), - std::move(appSession)); + std::make_shared<PowerHintSessionWrapper>(std::move(appSession))); } HalResult<int64_t> AidlHalWrapper::getHintSessionPreferredRate() { @@ -287,7 +277,7 @@ HalResult<Aidl::ChannelConfig> AidlHalWrapper::getSessionChannel(int tgid, int u } HalResult<void> AidlHalWrapper::closeSessionChannel(int tgid, int uid) { - return toHalResult(mHandle->closeSessionChannel(tgid, uid)); + return HalResult<void>::fromStatus(mHandle->closeSessionChannel(tgid, uid)); } const char* AidlHalWrapper::getUnsupportedMessage() { diff --git a/services/powermanager/PowerHintSessionWrapper.cpp b/services/powermanager/PowerHintSessionWrapper.cpp new file mode 100644 index 0000000000..930c7fa2b8 --- /dev/null +++ b/services/powermanager/PowerHintSessionWrapper.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2024 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. + */ + +#include <powermanager/PowerHintSessionWrapper.h> + +using namespace aidl::android::hardware::power; + +namespace android::power { + +// Caches support for a given call in a static variable, checking both +// the return value and interface version. +#define CACHE_SUPPORT(version, method) \ + ({ \ + static bool support = mInterfaceVersion >= version; \ + !support ? decltype(method)::unsupported() : ({ \ + auto result = method; \ + if (result.isUnsupported()) { \ + support = false; \ + } \ + std::move(result); \ + }); \ + }) + +#define CHECK_SESSION(resultType) \ + if (mSession == nullptr) { \ + return HalResult<resultType>::failed("Session not running"); \ + } + +// FWD_CALL just forwards calls from the wrapper to the session object. +// It only works if the call has no return object, as is the case with all calls +// except getSessionConfig. +#define FWD_CALL(version, name, args, untypedArgs) \ + HalResult<void> PowerHintSessionWrapper::name args { \ + CHECK_SESSION(void) \ + return CACHE_SUPPORT(version, HalResult<void>::fromStatus(mSession->name untypedArgs)); \ + } + +PowerHintSessionWrapper::PowerHintSessionWrapper(std::shared_ptr<IPowerHintSession>&& session) + : mSession(session) { + if (mSession != nullptr) { + mSession->getInterfaceVersion(&mInterfaceVersion); + } +} + +// Support for individual hints/modes is not really handled here since there +// is no way to check for it, so in the future if a way to check that is added, +// this will need to be updated. + +FWD_CALL(2, updateTargetWorkDuration, (int64_t in_targetDurationNanos), (in_targetDurationNanos)); +FWD_CALL(2, reportActualWorkDuration, (const std::vector<WorkDuration>& in_durations), + (in_durations)); +FWD_CALL(2, pause, (), ()); +FWD_CALL(2, resume, (), ()); +FWD_CALL(2, close, (), ()); +FWD_CALL(4, sendHint, (SessionHint in_hint), (in_hint)); +FWD_CALL(4, setThreads, (const std::vector<int32_t>& in_threadIds), (in_threadIds)); +FWD_CALL(5, setMode, (SessionMode in_type, bool in_enabled), (in_type, in_enabled)); + +HalResult<SessionConfig> PowerHintSessionWrapper::getSessionConfig() { + CHECK_SESSION(SessionConfig); + SessionConfig config; + return CACHE_SUPPORT(5, + HalResult<SessionConfig>::fromStatus(mSession->getSessionConfig(&config), + std::move(config))); +} + +} // namespace android::power diff --git a/services/powermanager/tests/Android.bp b/services/powermanager/tests/Android.bp index 6fc96c0959..a05ce2b39c 100644 --- a/services/powermanager/tests/Android.bp +++ b/services/powermanager/tests/Android.bp @@ -37,6 +37,7 @@ cc_test { "PowerHalWrapperHidlV1_1Test.cpp", "PowerHalWrapperHidlV1_2Test.cpp", "PowerHalWrapperHidlV1_3Test.cpp", + "PowerHintSessionWrapperTest.cpp", "WorkSourceTest.cpp", ], cflags: [ diff --git a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp index a7202969ad..1589c9937d 100644 --- a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp +++ b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp @@ -86,6 +86,10 @@ protected: void PowerHalWrapperAidlTest::SetUp() { mMockHal = ndk::SharedRefBase::make<StrictMock<MockIPower>>(); + EXPECT_CALL(*mMockHal, getInterfaceVersion(_)).WillRepeatedly(([](int32_t* ret) { + *ret = 5; + return ndk::ScopedAStatus::ok(); + })); mWrapper = std::make_unique<AidlHalWrapper>(mMockHal); ASSERT_NE(nullptr, mWrapper); } @@ -130,10 +134,12 @@ TEST_F(PowerHalWrapperAidlTest, TestSetBoostFailed) { } TEST_F(PowerHalWrapperAidlTest, TestSetBoostUnsupported) { - EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::INTERACTION), _)) - .Times(Exactly(1)) - .WillOnce(DoAll(SetArgPointee<1>(false), - Return(testing::ByMove(ndk::ScopedAStatus::ok())))); + EXPECT_CALL(*mMockHal.get(), isBoostSupported(_, _)) + .Times(Exactly(2)) + .WillRepeatedly([](Boost, bool* ret) { + *ret = false; + return ndk::ScopedAStatus::ok(); + }); auto result = mWrapper->setBoost(Boost::INTERACTION, 1000); ASSERT_TRUE(result.isUnsupported()); @@ -311,3 +317,29 @@ TEST_F(PowerHalWrapperAidlTest, TestSessionChannel) { auto closeResult = mWrapper->closeSessionChannel(tgid, uid); ASSERT_TRUE(closeResult.isOk()); } + +TEST_F(PowerHalWrapperAidlTest, TestCreateHintSessionWithConfigUnsupported) { + std::vector<int> threadIds{gettid()}; + int32_t tgid = 999; + int32_t uid = 1001; + int64_t durationNanos = 16666666L; + SessionTag tag = SessionTag::OTHER; + SessionConfig out; + EXPECT_CALL(*mMockHal.get(), + createHintSessionWithConfig(Eq(tgid), Eq(uid), Eq(threadIds), Eq(durationNanos), + Eq(tag), _, _)) + .Times(1) + .WillOnce(Return(testing::ByMove( + ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION)))); + auto result = + mWrapper->createHintSessionWithConfig(tgid, uid, threadIds, durationNanos, tag, &out); + ASSERT_TRUE(result.isUnsupported()); + Mock::VerifyAndClearExpectations(mMockHal.get()); + EXPECT_CALL(*mMockHal.get(), + createHintSessionWithConfig(Eq(tgid), Eq(uid), Eq(threadIds), Eq(durationNanos), + Eq(tag), _, _)) + .WillOnce(Return( + testing::ByMove(ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION)))); + result = mWrapper->createHintSessionWithConfig(tgid, uid, threadIds, durationNanos, tag, &out); + ASSERT_TRUE(result.isUnsupported()); +} diff --git a/services/powermanager/tests/PowerHintSessionWrapperTest.cpp b/services/powermanager/tests/PowerHintSessionWrapperTest.cpp new file mode 100644 index 0000000000..7743fa4363 --- /dev/null +++ b/services/powermanager/tests/PowerHintSessionWrapperTest.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2024 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. + */ + +#include <aidl/android/hardware/power/IPowerHintSession.h> +#include <powermanager/PowerHintSessionWrapper.h> + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +using aidl::android::hardware::power::IPowerHintSession; +using android::power::PowerHintSessionWrapper; + +using namespace android; +using namespace std::chrono_literals; +using namespace testing; + +class MockIPowerHintSession : public IPowerHintSession { +public: + MockIPowerHintSession() = default; + MOCK_METHOD(::ndk::ScopedAStatus, updateTargetWorkDuration, (int64_t in_targetDurationNanos), + (override)); + MOCK_METHOD(::ndk::ScopedAStatus, reportActualWorkDuration, + (const std::vector<::aidl::android::hardware::power::WorkDuration>& in_durations), + (override)); + MOCK_METHOD(::ndk::ScopedAStatus, pause, (), (override)); + MOCK_METHOD(::ndk::ScopedAStatus, resume, (), (override)); + MOCK_METHOD(::ndk::ScopedAStatus, close, (), (override)); + MOCK_METHOD(::ndk::ScopedAStatus, sendHint, + (::aidl::android::hardware::power::SessionHint in_hint), (override)); + MOCK_METHOD(::ndk::ScopedAStatus, setThreads, (const std::vector<int32_t>& in_threadIds), + (override)); + MOCK_METHOD(::ndk::ScopedAStatus, setMode, + (::aidl::android::hardware::power::SessionMode in_type, bool in_enabled), + (override)); + MOCK_METHOD(::ndk::ScopedAStatus, getSessionConfig, + (::aidl::android::hardware::power::SessionConfig * _aidl_return), (override)); + MOCK_METHOD(::ndk::ScopedAStatus, getInterfaceVersion, (int32_t * _aidl_return), (override)); + MOCK_METHOD(::ndk::ScopedAStatus, getInterfaceHash, (std::string * _aidl_return), (override)); + MOCK_METHOD(::ndk::SpAIBinder, asBinder, (), (override)); + MOCK_METHOD(bool, isRemote, (), (override)); +}; + +class PowerHintSessionWrapperTest : public Test { +public: + void SetUp() override; + +protected: + std::shared_ptr<NiceMock<MockIPowerHintSession>> mMockSession = nullptr; + std::unique_ptr<PowerHintSessionWrapper> mSession = nullptr; +}; + +void PowerHintSessionWrapperTest::SetUp() { + mMockSession = ndk::SharedRefBase::make<NiceMock<MockIPowerHintSession>>(); + EXPECT_CALL(*mMockSession, getInterfaceVersion(_)).WillRepeatedly(([](int32_t* ret) { + *ret = 5; + return ndk::ScopedAStatus::ok(); + })); + mSession = std::make_unique<PowerHintSessionWrapper>(mMockSession); + ASSERT_NE(nullptr, mSession); +} + +TEST_F(PowerHintSessionWrapperTest, updateTargetWorkDuration) { + EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(1000000000)) + .WillOnce(Return(ndk::ScopedAStatus::ok())); + auto status = mSession->updateTargetWorkDuration(1000000000); + ASSERT_TRUE(status.isOk()); +} + +TEST_F(PowerHintSessionWrapperTest, reportActualWorkDuration) { + EXPECT_CALL(*mMockSession.get(), + reportActualWorkDuration( + std::vector<::aidl::android::hardware::power::WorkDuration>())) + .WillOnce(Return(ndk::ScopedAStatus::ok())); + auto status = mSession->reportActualWorkDuration( + std::vector<::aidl::android::hardware::power::WorkDuration>()); + ASSERT_TRUE(status.isOk()); +} + +TEST_F(PowerHintSessionWrapperTest, pause) { + EXPECT_CALL(*mMockSession.get(), pause()).WillOnce(Return(ndk::ScopedAStatus::ok())); + auto status = mSession->pause(); + ASSERT_TRUE(status.isOk()); +} + +TEST_F(PowerHintSessionWrapperTest, resume) { + EXPECT_CALL(*mMockSession.get(), resume()).WillOnce(Return(ndk::ScopedAStatus::ok())); + auto status = mSession->resume(); + ASSERT_TRUE(status.isOk()); +} + +TEST_F(PowerHintSessionWrapperTest, close) { + EXPECT_CALL(*mMockSession.get(), close()).WillOnce(Return(ndk::ScopedAStatus::ok())); + auto status = mSession->close(); + ASSERT_TRUE(status.isOk()); +} + +TEST_F(PowerHintSessionWrapperTest, sendHint) { + EXPECT_CALL(*mMockSession.get(), + sendHint(::aidl::android::hardware::power::SessionHint::CPU_LOAD_UP)) + .WillOnce(Return(ndk::ScopedAStatus::ok())); + auto status = mSession->sendHint(::aidl::android::hardware::power::SessionHint::CPU_LOAD_UP); + ASSERT_TRUE(status.isOk()); +} + +TEST_F(PowerHintSessionWrapperTest, setThreads) { + EXPECT_CALL(*mMockSession.get(), setThreads(_)).WillOnce(Return(ndk::ScopedAStatus::ok())); + auto status = mSession->setThreads(std::vector<int32_t>{gettid()}); + ASSERT_TRUE(status.isOk()); +} + +TEST_F(PowerHintSessionWrapperTest, setMode) { + EXPECT_CALL(*mMockSession.get(), + setMode(::aidl::android::hardware::power::SessionMode::POWER_EFFICIENCY, true)) + .WillOnce(Return(ndk::ScopedAStatus::ok())); + auto status = mSession->setMode(::aidl::android::hardware::power::SessionMode::POWER_EFFICIENCY, + true); + ASSERT_TRUE(status.isOk()); +} + +TEST_F(PowerHintSessionWrapperTest, getSessionConfig) { + EXPECT_CALL(*mMockSession.get(), getSessionConfig(_)) + .WillOnce(DoAll(SetArgPointee<0>( + aidl::android::hardware::power::SessionConfig{.id = 12L}), + Return(ndk::ScopedAStatus::ok()))); + auto status = mSession->getSessionConfig(); + ASSERT_TRUE(status.isOk()); +} diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp index a0c943ba72..8dfbeb80cd 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp @@ -233,7 +233,7 @@ void PowerAdvisor::updateTargetWorkDuration(Duration targetDuration) { auto ret = mHintSession->updateTargetWorkDuration(targetDuration.ns()); if (!ret.isOk()) { ALOGW("Failed to set power hint target work duration with error: %s", - ret.getDescription().c_str()); + ret.errorMessage()); mHintSession = nullptr; } } @@ -293,8 +293,7 @@ void PowerAdvisor::reportActualWorkDuration() { auto ret = mHintSession->reportActualWorkDuration(mHintSessionQueue); if (!ret.isOk()) { - ALOGW("Failed to report actual work durations with error: %s", - ret.getDescription().c_str()); + ALOGW("Failed to report actual work durations with error: %s", ret.errorMessage()); mHintSession = nullptr; return; } diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h index bbe51cc09d..1040048b13 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h @@ -259,8 +259,8 @@ private: std::optional<bool> mSupportsHintSession; std::mutex mHintSessionMutex; - std::shared_ptr<aidl::android::hardware::power::IPowerHintSession> mHintSession - GUARDED_BY(mHintSessionMutex) = nullptr; + std::shared_ptr<power::PowerHintSessionWrapper> mHintSession GUARDED_BY(mHintSessionMutex) = + nullptr; // Initialize to true so we try to call, to check if it's supported bool mHasExpensiveRendering = true; diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index f529f7cb05..08cfc55bf9 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -29,7 +29,7 @@ filegroup { "mock/DisplayHardware/MockComposer.cpp", "mock/DisplayHardware/MockHWC2.cpp", "mock/DisplayHardware/MockIPower.cpp", - "mock/DisplayHardware/MockIPowerHintSession.cpp", + "mock/DisplayHardware/MockPowerHintSessionWrapper.cpp", "mock/DisplayHardware/MockPowerAdvisor.cpp", "mock/MockEventThread.cpp", "mock/MockFrameTimeline.cpp", diff --git a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp index 9c66a97573..1d44a3ef77 100644 --- a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp +++ b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp @@ -26,8 +26,8 @@ #include <chrono> #include <future> #include "TestableSurfaceFlinger.h" -#include "mock/DisplayHardware/MockIPowerHintSession.h" #include "mock/DisplayHardware/MockPowerHalController.h" +#include "mock/DisplayHardware/MockPowerHintSessionWrapper.h" using namespace android; using namespace android::Hwc2::mock; @@ -54,7 +54,7 @@ protected: TestableSurfaceFlinger mFlinger; std::unique_ptr<PowerAdvisor> mPowerAdvisor; MockPowerHalController* mMockPowerHalController; - std::shared_ptr<MockIPowerHintSession> mMockPowerHintSession; + std::shared_ptr<MockPowerHintSessionWrapper> mMockPowerHintSession; }; bool PowerAdvisorTest::sessionExists() { @@ -68,25 +68,29 @@ void PowerAdvisorTest::SetUp() { mMockPowerHalController = reinterpret_cast<MockPowerHalController*>(mPowerAdvisor->mPowerHal.get()); ON_CALL(*mMockPowerHalController, getHintSessionPreferredRate) - .WillByDefault(Return(HalResult<int64_t>::fromStatus(binder::Status::ok(), 16000))); + .WillByDefault(Return( + ByMove(HalResult<int64_t>::fromStatus(ndk::ScopedAStatus::ok(), 16000)))); } void PowerAdvisorTest::startPowerHintSession(bool returnValidSession) { - mMockPowerHintSession = ndk::SharedRefBase::make<NiceMock<MockIPowerHintSession>>(); + mMockPowerHintSession = std::make_shared<NiceMock<MockPowerHintSessionWrapper>>(); if (returnValidSession) { ON_CALL(*mMockPowerHalController, createHintSession) - .WillByDefault( - Return(HalResult<std::shared_ptr<IPowerHintSession>>:: - fromStatus(binder::Status::ok(), mMockPowerHintSession))); + .WillByDefault([&](int32_t, int32_t, const std::vector<int32_t>&, int64_t) { + return HalResult<std::shared_ptr<PowerHintSessionWrapper>>:: + fromStatus(ndk::ScopedAStatus::ok(), mMockPowerHintSession); + }); } else { - ON_CALL(*mMockPowerHalController, createHintSession) - .WillByDefault(Return(HalResult<std::shared_ptr<IPowerHintSession>>:: - fromStatus(binder::Status::ok(), nullptr))); + ON_CALL(*mMockPowerHalController, createHintSession).WillByDefault([] { + return HalResult< + std::shared_ptr<PowerHintSessionWrapper>>::fromStatus(ndk::ScopedAStatus::ok(), + nullptr); + }); } mPowerAdvisor->enablePowerHintSession(true); mPowerAdvisor->startPowerHintSession({1, 2, 3}); ON_CALL(*mMockPowerHintSession, updateTargetWorkDuration) - .WillByDefault(Return(testing::ByMove(ndk::ScopedAStatus::ok()))); + .WillByDefault(Return(testing::ByMove(HalResult<void>::ok()))); } void PowerAdvisorTest::setExpectedTiming(Duration totalFrameTargetDuration, @@ -148,7 +152,7 @@ TEST_F(PowerAdvisorTest, hintSessionUseHwcDisplay) { reportActualWorkDuration(ElementsAre( Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns()))))) .Times(1) - .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok()))); + .WillOnce(Return(testing::ByMove(HalResult<void>::ok()))); fakeBasicFrameTiming(startTime, vsyncPeriod); setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod); mPowerAdvisor->setDisplays(displayIds); @@ -188,7 +192,7 @@ TEST_F(PowerAdvisorTest, hintSessionSubtractsHwcFenceTime) { reportActualWorkDuration(ElementsAre( Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns()))))) .Times(1) - .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok()))); + .WillOnce(Return(testing::ByMove(HalResult<void>::ok()))); fakeBasicFrameTiming(startTime, vsyncPeriod); setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod); @@ -231,7 +235,7 @@ TEST_F(PowerAdvisorTest, hintSessionUsingSecondaryVirtualDisplays) { reportActualWorkDuration(ElementsAre( Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns()))))) .Times(1) - .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok()))); + .WillOnce(Return(testing::ByMove(HalResult<void>::ok()))); fakeBasicFrameTiming(startTime, vsyncPeriod); setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod); @@ -328,17 +332,17 @@ TEST_F(PowerAdvisorTest, hintSessionTestNotifyReportRace) { ON_CALL(*mMockPowerHintSession, sendHint).WillByDefault([&letSendHintFinish] { letSendHintFinish.get_future().wait(); - return ndk::ScopedAStatus::fromExceptionCode(-127); + return HalResult<void>::fromStatus(ndk::ScopedAStatus::fromExceptionCode(-127)); }); ON_CALL(*mMockPowerHintSession, reportActualWorkDuration).WillByDefault([] { - return ndk::ScopedAStatus::fromExceptionCode(-127); + return HalResult<void>::fromStatus(ndk::ScopedAStatus::fromExceptionCode(-127)); }); - ON_CALL(*mMockPowerHalController, createHintSession) - .WillByDefault(Return( - HalResult<std::shared_ptr<IPowerHintSession>>:: - fromStatus(ndk::ScopedAStatus::fromExceptionCode(-127), nullptr))); + ON_CALL(*mMockPowerHalController, createHintSession).WillByDefault([] { + return HalResult<std::shared_ptr<PowerHintSessionWrapper>>:: + fromStatus(ndk::ScopedAStatus::fromExceptionCode(-127), nullptr); + }); // First background call, to notice the session is down auto firstHint = std::async(std::launch::async, [this] { diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h deleted file mode 100644 index 27564b26de..0000000000 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2022 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. - */ - -#pragma once - -#include "binder/Status.h" - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#include <aidl/android/hardware/power/IPower.h> -#pragma clang diagnostic pop - -#include <gmock/gmock.h> - -using aidl::android::hardware::power::IPowerHintSession; -using aidl::android::hardware::power::SessionConfig; -using aidl::android::hardware::power::SessionHint; -using aidl::android::hardware::power::SessionMode; -using android::binder::Status; - -using namespace aidl::android::hardware::power; - -namespace android::Hwc2::mock { - -class MockIPowerHintSession : public IPowerHintSession { -public: - MockIPowerHintSession(); - - MOCK_METHOD(ndk::SpAIBinder, asBinder, (), (override)); - MOCK_METHOD(ndk::ScopedAStatus, pause, (), (override)); - MOCK_METHOD(ndk::ScopedAStatus, resume, (), (override)); - MOCK_METHOD(ndk::ScopedAStatus, close, (), (override)); - MOCK_METHOD(ndk::ScopedAStatus, getInterfaceVersion, (int32_t * version), (override)); - MOCK_METHOD(ndk::ScopedAStatus, getInterfaceHash, (std::string * hash), (override)); - MOCK_METHOD(bool, isRemote, (), (override)); - MOCK_METHOD(ndk::ScopedAStatus, updateTargetWorkDuration, (int64_t), (override)); - MOCK_METHOD(ndk::ScopedAStatus, reportActualWorkDuration, (const ::std::vector<WorkDuration>&), - (override)); - MOCK_METHOD(ndk::ScopedAStatus, sendHint, (SessionHint), (override)); - MOCK_METHOD(ndk::ScopedAStatus, setThreads, (const ::std::vector<int32_t>&), (override)); - MOCK_METHOD(ndk::ScopedAStatus, setMode, (SessionMode, bool), (override)); - MOCK_METHOD(ndk::ScopedAStatus, getSessionConfig, (SessionConfig * _aidl_return), (override)); -}; - -} // namespace android::Hwc2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h index ae41e7ea75..af1862d1cf 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h @@ -44,10 +44,10 @@ public: MOCK_METHOD(HalResult<void>, setBoost, (aidl::android::hardware::power::Boost, int32_t), (override)); MOCK_METHOD(HalResult<void>, setMode, (aidl::android::hardware::power::Mode, bool), (override)); - MOCK_METHOD(HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>>, + MOCK_METHOD(HalResult<std::shared_ptr<android::power::PowerHintSessionWrapper>>, createHintSession, (int32_t, int32_t, const std::vector<int32_t>&, int64_t), (override)); - MOCK_METHOD(HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>>, + MOCK_METHOD(HalResult<std::shared_ptr<android::power::PowerHintSessionWrapper>>, createHintSessionWithConfig, (int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos, aidl::android::hardware::power::SessionTag tag, diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHintSessionWrapper.cpp index 770bc15869..d383283d8e 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.cpp +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHintSessionWrapper.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022 The Android Open Source Project + * Copyright 2024 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. @@ -14,11 +14,12 @@ * limitations under the License. */ -#include "mock/DisplayHardware/MockIPowerHintSession.h" +#include "mock/DisplayHardware/MockPowerHintSessionWrapper.h" namespace android::Hwc2::mock { // Explicit default instantiation is recommended. -MockIPowerHintSession::MockIPowerHintSession() = default; +MockPowerHintSessionWrapper::MockPowerHintSessionWrapper() + : power::PowerHintSessionWrapper(nullptr) {} } // namespace android::Hwc2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHintSessionWrapper.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHintSessionWrapper.h new file mode 100644 index 0000000000..bc6950cccb --- /dev/null +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHintSessionWrapper.h @@ -0,0 +1,55 @@ +/* + * Copyright 2024 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. + */ + +#pragma once + +#include "binder/Status.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#include <aidl/android/hardware/power/IPower.h> +#include <powermanager/PowerHintSessionWrapper.h> +#pragma clang diagnostic pop + +#include <gmock/gmock.h> + +using aidl::android::hardware::power::IPowerHintSession; +using aidl::android::hardware::power::SessionConfig; +using aidl::android::hardware::power::SessionHint; +using aidl::android::hardware::power::SessionMode; +using android::binder::Status; + +using namespace aidl::android::hardware::power; + +namespace android::Hwc2::mock { + +class MockPowerHintSessionWrapper : public power::PowerHintSessionWrapper { +public: + MockPowerHintSessionWrapper(); + + MOCK_METHOD(power::HalResult<void>, updateTargetWorkDuration, (int64_t), (override)); + MOCK_METHOD(power::HalResult<void>, reportActualWorkDuration, + (const ::std::vector<WorkDuration>&), (override)); + MOCK_METHOD(power::HalResult<void>, pause, (), (override)); + MOCK_METHOD(power::HalResult<void>, resume, (), (override)); + MOCK_METHOD(power::HalResult<void>, close, (), (override)); + MOCK_METHOD(power::HalResult<void>, sendHint, (SessionHint), (override)); + MOCK_METHOD(power::HalResult<void>, setThreads, (const ::std::vector<int32_t>&), (override)); + MOCK_METHOD(power::HalResult<void>, setMode, (SessionMode, bool), (override)); + MOCK_METHOD(power::HalResult<SessionConfig>, getSessionConfig, (), (override)); +}; + +} // namespace android::Hwc2::mock |