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
diff --git a/include/powermanager/HalResult.h b/include/powermanager/HalResult.h
new file mode 100644
index 0000000..7fe3822
--- /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 c50bc4a..7e0bd5b 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 @@
virtual std::unique_ptr<HalWrapper> connect();
virtual void reset();
+ virtual int32_t getAidlVersion();
};
// -------------------------------------------------------------------------------------------------
@@ -59,14 +61,13 @@
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 cbbfa59..ab66336 100644
--- a/include/powermanager/PowerHalLoader.h
+++ b/include/powermanager/PowerHalLoader.h
@@ -36,6 +36,8 @@
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 @@
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 e2da014..6e347a9 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 @@
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 @@
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 @@
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 @@
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 @@
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 0000000..ba6fe77
--- /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 1f72e8b..3ea08fe 100644
--- a/services/powermanager/Android.bp
+++ b/services/powermanager/Android.bp
@@ -17,6 +17,7 @@
"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 bc178bc..40fd097 100644
--- a/services/powermanager/PowerHalController.cpp
+++ b/services/powermanager/PowerHalController.cpp
@@ -57,6 +57,10 @@
PowerHalLoader::unloadAll();
}
+int32_t HalConnector::getAidlVersion() {
+ return PowerHalLoader::getAidlVersion();
+}
+
// -------------------------------------------------------------------------------------------------
void PowerHalController::init() {
@@ -77,6 +81,22 @@
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 @@
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 2214461..ea284c3 100644
--- a/services/powermanager/PowerHalLoader.cpp
+++ b/services/powermanager/PowerHalLoader.cpp
@@ -60,6 +60,7 @@
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 @@
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 @@
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 1009100..bd6685c 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 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 @@
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 @@
}
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 @@
}
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<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 0000000..930c7fa
--- /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 6fc96c0..a05ce2b 100644
--- a/services/powermanager/tests/Android.bp
+++ b/services/powermanager/tests/Android.bp
@@ -37,6 +37,7 @@
"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 a720296..1589c99 100644
--- a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
+++ b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
@@ -86,6 +86,10 @@
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, 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 @@
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 0000000..7743fa4
--- /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 a0c943b..8dfbeb8 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -233,7 +233,7 @@
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 @@
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 bbe51cc0..1040048 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -259,8 +259,8 @@
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 f529f7c..08cfc55 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -29,7 +29,7 @@
"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 9c66a97..1d44a3e 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 27564b2..0000000
--- 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 ae41e7e..af1862d 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h
@@ -44,10 +44,10 @@
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
similarity index 75%
rename from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.cpp
rename to services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHintSessionWrapper.cpp
index 770bc15..d383283 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 0000000..bc6950c
--- /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