diff options
-rw-r--r-- | include/powermanager/PowerHalWrapper.h | 128 | ||||
-rw-r--r-- | services/powermanager/Android.bp | 28 | ||||
-rw-r--r-- | services/powermanager/PowerHalWrapper.cpp | 172 | ||||
-rw-r--r-- | services/powermanager/TEST_MAPPING | 10 | ||||
-rw-r--r-- | services/powermanager/tests/Android.bp | 61 | ||||
-rw-r--r-- | services/powermanager/tests/IThermalManagerTest.cpp (renamed from services/powermanager/IThermalManagerTest.cpp) | 0 | ||||
-rw-r--r-- | services/powermanager/tests/PowerHalWrapperAidlTest.cpp | 202 | ||||
-rw-r--r-- | services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp | 145 | ||||
-rw-r--r-- | services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp | 165 |
9 files changed, 890 insertions, 21 deletions
diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h new file mode 100644 index 0000000000..6d8a6eb0f6 --- /dev/null +++ b/include/powermanager/PowerHalWrapper.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_POWERHALWRAPPER_H +#define ANDROID_POWERHALWRAPPER_H + +#include <android-base/thread_annotations.h> + +#include <android/hardware/power/1.1/IPower.h> +#include <android/hardware/power/Boost.h> +#include <android/hardware/power/IPower.h> +#include <android/hardware/power/Mode.h> + +using android::hardware::power::Boost; +using android::hardware::power::Mode; +using android::hardware::power::V1_0::Feature; +using android::hardware::power::V1_0::PowerHint; +using IPowerV1_1 = android::hardware::power::V1_1::IPower; +using IPowerV1_0 = android::hardware::power::V1_0::IPower; +using IPowerAidl = android::hardware::power::IPower; + +namespace android { + +// State of Power HAL support for individual apis. +enum class PowerHalSupport { + UNKNOWN = 0, + ON = 1, + OFF = 2, +}; + +// State of the Power HAL api call result. +enum class PowerHalResult { + SUCCESSFUL = 0, + FAILED = 1, + UNSUPPORTED = 2, +}; + +// Wrapper for Power HAL handlers. +class PowerHalWrapper { +public: + virtual ~PowerHalWrapper() = default; + + virtual PowerHalResult setBoost(Boost boost, int32_t durationMs) = 0; + virtual PowerHalResult setMode(Mode mode, bool enabled) = 0; +}; + +// Empty Power HAL wrapper that ignores all api calls. +class EmptyPowerHalWrapper : public PowerHalWrapper { +public: + EmptyPowerHalWrapper() = default; + ~EmptyPowerHalWrapper() = default; + + PowerHalResult setBoost(Boost boost, int32_t durationMs) override; + PowerHalResult setMode(Mode mode, bool enabled) override; +}; + +// Wrapper for the HIDL Power HAL v1.0. +class HidlPowerHalWrapperV1_0 : public PowerHalWrapper { +public: + explicit HidlPowerHalWrapperV1_0(sp<IPowerV1_0> powerHal) : handleV1_0(std::move(powerHal)) {} + virtual ~HidlPowerHalWrapperV1_0() = default; + + PowerHalResult setBoost(Boost boost, int32_t durationMs) override; + PowerHalResult setMode(Mode mode, bool enabled) override; + +protected: + virtual PowerHalResult sendPowerHint(PowerHint hintId, uint32_t data); + +private: + sp<IPowerV1_0> handleV1_0; + PowerHalResult setInteractive(bool enabled); + PowerHalResult setFeature(Feature feature, bool enabled); +}; + +// Wrapper for the HIDL Power HAL v1.1. +class HidlPowerHalWrapperV1_1 : public HidlPowerHalWrapperV1_0 { +public: + HidlPowerHalWrapperV1_1(sp<IPowerV1_0> powerHalV1_0, sp<IPowerV1_1> powerHalV1_1) + : HidlPowerHalWrapperV1_0(powerHalV1_0), handleV1_1(std::move(powerHalV1_1)) {} + ~HidlPowerHalWrapperV1_1() = default; + +protected: + virtual PowerHalResult sendPowerHint(PowerHint hintId, uint32_t data) override; + +private: + sp<IPowerV1_1> handleV1_1; +}; + +// Wrapper for the AIDL Power HAL. +class AidlPowerHalWrapper : public PowerHalWrapper { +public: + explicit AidlPowerHalWrapper(sp<IPowerAidl> powerHal) : handle(std::move(powerHal)) {} + ~AidlPowerHalWrapper() = default; + + PowerHalResult setBoost(Boost boost, int32_t durationMs) override; + PowerHalResult setMode(Mode mode, bool enabled) override; + +private: + // Control access to the boost and mode supported arrays. + std::mutex mBoostMutex; + std::mutex mModeMutex; + sp<IPowerAidl> handle; + // Android framework only sends boost upto DISPLAY_UPDATE_IMMINENT. + // Need to increase the array size if more boost supported. + std::array<std::atomic<PowerHalSupport>, static_cast<int32_t>(Boost::DISPLAY_UPDATE_IMMINENT)+1> + boostSupportedArray GUARDED_BY(mBoostMutex) = {PowerHalSupport::UNKNOWN}; + // Android framework only sends mode upto DISPLAY_INACTIVE. + // Need to increase the array if more mode supported. + std::array<std::atomic<PowerHalSupport>, static_cast<int32_t>(Mode::DISPLAY_INACTIVE)+1> + modeSupportedArray GUARDED_BY(mModeMutex) = {PowerHalSupport::UNKNOWN}; +}; + +}; // namespace android + +#endif // ANDROID_POWERHALWRAPPER_H diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp index c62f327b3c..cff4a029e6 100644 --- a/services/powermanager/Android.bp +++ b/services/powermanager/Android.bp @@ -4,6 +4,7 @@ cc_library_shared { srcs: [ "BatterySaverPolicyConfig.cpp", "CoolingDevice.cpp", + "PowerHalWrapper.cpp", "PowerSaveState.cpp", "Temperature.cpp", "WorkSource.cpp", @@ -19,9 +20,13 @@ cc_library_shared { }, shared_libs: [ - "libutils", "libbinder", - "liblog" + "libhidlbase", + "liblog", + "libutils", + "android.hardware.power@1.0", + "android.hardware.power@1.1", + "android.hardware.power-cpp", ], cflags: [ @@ -36,22 +41,3 @@ cc_library_shared { "include", ], } - -cc_test { - name: "thermalmanager-test", - srcs: ["IThermalManagerTest.cpp", - ], - cflags: [ - "-Wall", - "-Werror", - "-Wextra", - ], - shared_libs: [ - "libbase", - "libbinder", - "libhidlbase", - "liblog", - "libpowermanager", - "libutils", - ], -} diff --git a/services/powermanager/PowerHalWrapper.cpp b/services/powermanager/PowerHalWrapper.cpp new file mode 100644 index 0000000000..d959a2cc96 --- /dev/null +++ b/services/powermanager/PowerHalWrapper.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "PowerHalWrapper" +#include <utils/Log.h> + +#include <android/hardware/power/Boost.h> +#include <android/hardware/power/Mode.h> + +#include <powermanager/PowerHalWrapper.h> + +using android::hardware::power::Boost; +using android::hardware::power::Mode; +using android::hardware::power::V1_0::Feature; +using android::hardware::power::V1_0::PowerHint; + +namespace android { + +// ------------------------------------------------------------------------------------------------- + +PowerHalResult EmptyPowerHalWrapper::setBoost(Boost boost, int32_t durationMs) { + ALOGV("Skipped setBoost %s with duration %dms because Power HAL not available", + toString(boost).c_str(), durationMs); + return PowerHalResult::UNSUPPORTED; +} + +PowerHalResult EmptyPowerHalWrapper::setMode(Mode mode, bool enabled) { + ALOGV("Skipped setMode %s to %s because Power HAL not available", + toString(mode).c_str(), enabled ? "true" : "false"); + return PowerHalResult::UNSUPPORTED; +} + +// ------------------------------------------------------------------------------------------------- + +PowerHalResult HidlPowerHalWrapperV1_0::setBoost(Boost boost, int32_t durationMs) { + if (boost == Boost::INTERACTION) { + return sendPowerHint(PowerHint::INTERACTION, durationMs); + } else { + ALOGV("Skipped setBoost %s because Power HAL AIDL not available", + toString(boost).c_str()); + return PowerHalResult::UNSUPPORTED; + } +} + +PowerHalResult HidlPowerHalWrapperV1_0::setMode(Mode mode, bool enabled) { + uint32_t data = enabled ? 1 : 0; + switch (mode) { + case Mode::LAUNCH: + return sendPowerHint(PowerHint::LAUNCH, data); + case Mode::LOW_POWER: + return sendPowerHint(PowerHint::LOW_POWER, data); + case Mode::SUSTAINED_PERFORMANCE: + return sendPowerHint(PowerHint::SUSTAINED_PERFORMANCE, data); + case Mode::VR: + return sendPowerHint(PowerHint::VR_MODE, data); + case Mode::INTERACTIVE: + return setInteractive(enabled); + case Mode::DOUBLE_TAP_TO_WAKE: + return setFeature(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE, enabled); + default: + ALOGV("Skipped setMode %s because Power HAL AIDL not available", + toString(mode).c_str()); + return PowerHalResult::UNSUPPORTED; + } +} + +PowerHalResult HidlPowerHalWrapperV1_0::sendPowerHint(PowerHint hintId, uint32_t data) { + auto ret = handleV1_0->powerHint(hintId, data); + return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED; +} + +PowerHalResult HidlPowerHalWrapperV1_0::setInteractive(bool enabled) { + auto ret = handleV1_0->setInteractive(enabled); + return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED; +} + +PowerHalResult HidlPowerHalWrapperV1_0::setFeature(Feature feature, bool enabled) { + auto ret = handleV1_0->setFeature(feature, enabled); + return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED; +} + +// ------------------------------------------------------------------------------------------------- + +PowerHalResult HidlPowerHalWrapperV1_1::sendPowerHint(PowerHint hintId, uint32_t data) { + auto ret = handleV1_1->powerHintAsync(hintId, data); + return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED; +} + +// ------------------------------------------------------------------------------------------------- + +PowerHalResult AidlPowerHalWrapper::setBoost(Boost boost, int32_t durationMs) { + std::unique_lock<std::mutex> lock(mBoostMutex); + // Quick return if boost is not supported by HAL + if (boost > Boost::DISPLAY_UPDATE_IMMINENT || + boostSupportedArray[static_cast<int32_t>(boost)] == PowerHalSupport::OFF) { + ALOGV("Skipped setBoost %s because Power HAL doesn't support it", + toString(boost).c_str()); + return PowerHalResult::UNSUPPORTED; + } + + if (boostSupportedArray[static_cast<int32_t>(boost)] == PowerHalSupport::UNKNOWN) { + bool isSupported = false; + auto isSupportedRet = handle->isBoostSupported(boost, &isSupported); + if (!isSupportedRet.isOk()) { + ALOGV("Skipped setBoost %s because Power HAL is not available to check support", + toString(boost).c_str()); + return PowerHalResult::FAILED; + } + + boostSupportedArray[static_cast<int32_t>(boost)] = + isSupported ? PowerHalSupport::ON : PowerHalSupport::OFF; + if (!isSupported) { + ALOGV("Skipped setBoost %s because Power HAL doesn't support it", + toString(boost).c_str()); + return PowerHalResult::UNSUPPORTED; + } + } + lock.unlock(); + + auto ret = handle->setBoost(boost, durationMs); + return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED; +} + +PowerHalResult AidlPowerHalWrapper::setMode(Mode mode, bool enabled) { + std::unique_lock<std::mutex> lock(mModeMutex); + // Quick return if mode is not supported by HAL + if (mode > Mode::DISPLAY_INACTIVE || + modeSupportedArray[static_cast<int32_t>(mode)] == PowerHalSupport::OFF) { + ALOGV("Skipped setMode %s because Power HAL doesn't support it", + toString(mode).c_str()); + return PowerHalResult::UNSUPPORTED; + } + + if (modeSupportedArray[static_cast<int32_t>(mode)] == PowerHalSupport::UNKNOWN) { + bool isSupported = false; + auto isSupportedRet = handle->isModeSupported(mode, &isSupported); + if (!isSupportedRet.isOk()) { + ALOGV("Skipped setMode %s because Power HAL is not available to check support", + toString(mode).c_str()); + return PowerHalResult::FAILED; + } + + modeSupportedArray[static_cast<int32_t>(mode)] = + isSupported ? PowerHalSupport::ON : PowerHalSupport::OFF; + if (!isSupported) { + ALOGV("Skipped setMode %s because Power HAL doesn't support it", + toString(mode).c_str()); + return PowerHalResult::UNSUPPORTED; + } + } + lock.unlock(); + + auto ret = handle->setMode(mode, enabled); + return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED; +} + +// ------------------------------------------------------------------------------------------------- + +}; // namespace android diff --git a/services/powermanager/TEST_MAPPING b/services/powermanager/TEST_MAPPING new file mode 100644 index 0000000000..9a67901c5f --- /dev/null +++ b/services/powermanager/TEST_MAPPING @@ -0,0 +1,10 @@ +{ + "presubmit": [ + { + "name": "powermanager_test" + }, + { + "name": "thermalmanager_test" + } + ] +} diff --git a/services/powermanager/tests/Android.bp b/services/powermanager/tests/Android.bp new file mode 100644 index 0000000000..65cde03070 --- /dev/null +++ b/services/powermanager/tests/Android.bp @@ -0,0 +1,61 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_test { + name: "powermanager_test", + test_suites: ["device-tests"], + srcs: [ + "PowerHalWrapperAidlTest.cpp", + "PowerHalWrapperHidlV1_0Test.cpp", + "PowerHalWrapperHidlV1_1Test.cpp", + ], + cflags: [ + "-Wall", + "-Werror", + "-Wextra", + ], + shared_libs: [ + "libbase", + "libbinder", + "libhidlbase", + "liblog", + "libpowermanager", + "libutils", + "android.hardware.power@1.0", + "android.hardware.power@1.1", + "android.hardware.power-cpp", + ], + static_libs: [ + "libgmock", + ], +} + +cc_test { + name: "thermalmanager_test", + test_suites: ["device-tests"], + srcs: ["IThermalManagerTest.cpp",], + cflags: [ + "-Wall", + "-Werror", + "-Wextra", + ], + shared_libs: [ + "libbase", + "libhidlbase", + "liblog", + "libpowermanager", + "libbinder", + "libutils", + ], +} diff --git a/services/powermanager/IThermalManagerTest.cpp b/services/powermanager/tests/IThermalManagerTest.cpp index 575b9ee1c4..575b9ee1c4 100644 --- a/services/powermanager/IThermalManagerTest.cpp +++ b/services/powermanager/tests/IThermalManagerTest.cpp diff --git a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp new file mode 100644 index 0000000000..73b7466670 --- /dev/null +++ b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "PowerHalWrapperAidlTest" + +#include <android/hardware/power/Boost.h> +#include <android/hardware/power/Mode.h> +#include <binder/IServiceManager.h> + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <powermanager/PowerHalWrapper.h> + +#include <thread> +#include <utils/Log.h> + +using android::binder::Status; +using android::hardware::power::Boost; +using android::hardware::power::IPower; +using android::hardware::power::Mode; + +using namespace android; +using namespace std::chrono_literals; +using namespace testing; + +// ------------------------------------------------------------------------------------------------- + +class MockIPower : public IPower { +public: + MOCK_METHOD(Status, isBoostSupported, (Boost boost, bool* ret), (override)); + MOCK_METHOD(Status, setBoost, (Boost boost, int32_t durationMs), (override)); + MOCK_METHOD(Status, isModeSupported, (Mode mode, bool* ret), (override)); + MOCK_METHOD(Status, setMode, (Mode mode, bool enabled), (override)); + MOCK_METHOD(int32_t, getInterfaceVersion, (), (override)); + MOCK_METHOD(std::string, getInterfaceHash, (), (override)); + MOCK_METHOD(IBinder*, onAsBinder, (), (override)); +}; + +// ------------------------------------------------------------------------------------------------- + +class PowerHalWrapperAidlTest : public Test { +public: + void SetUp() override; + +protected: + std::unique_ptr<PowerHalWrapper> mWrapper = nullptr; + sp<StrictMock<MockIPower>> mMockHal = nullptr; +}; + +// ------------------------------------------------------------------------------------------------- + +void PowerHalWrapperAidlTest::SetUp() { + mMockHal = new StrictMock<MockIPower>(); + mWrapper = std::make_unique<AidlPowerHalWrapper>(mMockHal); + ASSERT_NE(mWrapper, nullptr); +} + +// ------------------------------------------------------------------------------------------------- + +TEST_F(PowerHalWrapperAidlTest, TestSetBoostSuccessful) { + { + InSequence seq; + EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::DISPLAY_UPDATE_IMMINENT), _)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status()))); + EXPECT_CALL(*mMockHal.get(), setBoost(Eq(Boost::DISPLAY_UPDATE_IMMINENT), Eq(100))) + .Times(Exactly(1)); + } + + auto result = mWrapper->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 100); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); +} + +TEST_F(PowerHalWrapperAidlTest, TestSetBoostFailed) { + { + InSequence seq; + EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::INTERACTION), _)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status()))); + EXPECT_CALL(*mMockHal.get(), setBoost(Eq(Boost::INTERACTION), Eq(100))) + .Times(Exactly(1)) + .WillRepeatedly(Return(Status::fromExceptionCode(-1))); + EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::DISPLAY_UPDATE_IMMINENT), _)) + .Times(Exactly(1)) + .WillRepeatedly(Return(Status::fromExceptionCode(-1))); + } + + auto result = mWrapper->setBoost(Boost::INTERACTION, 100); + ASSERT_EQ(PowerHalResult::FAILED, result); + result = mWrapper->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 1000); + ASSERT_EQ(PowerHalResult::FAILED, result); +} + +TEST_F(PowerHalWrapperAidlTest, TestSetBoostUnsupported) { + EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::INTERACTION), _)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<1>(false), Return(Status()))); + + auto result = mWrapper->setBoost(Boost::INTERACTION, 1000); + ASSERT_EQ(PowerHalResult::UNSUPPORTED, result); + result = mWrapper->setBoost(Boost::CAMERA_SHOT, 10); + ASSERT_EQ(PowerHalResult::UNSUPPORTED, result); +} + +TEST_F(PowerHalWrapperAidlTest, TestSetBoostMultiThreadCheckSupportedOnlyOnce) { + { + InSequence seq; + EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::INTERACTION), _)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status()))); + EXPECT_CALL(*mMockHal.get(), setBoost(Eq(Boost::INTERACTION), Eq(100))) + .Times(Exactly(10)); + } + + std::vector<std::thread> threads; + for (int i = 0; i < 10; i++) { + threads.push_back(std::thread([&]() { + auto result = mWrapper->setBoost(Boost::INTERACTION, 100); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + })); + } + std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); }); +} + +TEST_F(PowerHalWrapperAidlTest, TestSetModeSuccessful) { + { + InSequence seq; + EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::DISPLAY_INACTIVE), _)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status()))); + EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::DISPLAY_INACTIVE), Eq(false))) + .Times(Exactly(1)); + } + + auto result = mWrapper->setMode(Mode::DISPLAY_INACTIVE, false); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); +} + +TEST_F(PowerHalWrapperAidlTest, TestSetModeFailed) { + { + InSequence seq; + EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::LAUNCH), _)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status()))); + EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::LAUNCH), Eq(true))) + .Times(Exactly(1)) + .WillRepeatedly(Return(Status::fromExceptionCode(-1))); + EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::DISPLAY_INACTIVE), _)) + .Times(Exactly(1)) + .WillRepeatedly(Return(Status::fromExceptionCode(-1))); + } + + auto result = mWrapper->setMode(Mode::LAUNCH, true); + ASSERT_EQ(PowerHalResult::FAILED, result); + result = mWrapper->setMode(Mode::DISPLAY_INACTIVE, false); + ASSERT_EQ(PowerHalResult::FAILED, result); +} + +TEST_F(PowerHalWrapperAidlTest, TestSetModeUnsupported) { + EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::LAUNCH), _)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<1>(false), Return(Status()))); + + auto result = mWrapper->setMode(Mode::LAUNCH, true); + ASSERT_EQ(PowerHalResult::UNSUPPORTED, result); + result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true); + ASSERT_EQ(PowerHalResult::UNSUPPORTED, result); +} + +TEST_F(PowerHalWrapperAidlTest, TestSetModeMultiThreadCheckSupportedOnlyOnce) { + { + InSequence seq; + EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::LAUNCH), _)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status()))); + EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::LAUNCH), Eq(false))) + .Times(Exactly(10)); + } + + std::vector<std::thread> threads; + for (int i = 0; i < 10; i++) { + threads.push_back(std::thread([&]() { + auto result = mWrapper->setMode(Mode::LAUNCH, false); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + })); + } + std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); }); +} diff --git a/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp b/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp new file mode 100644 index 0000000000..5379054493 --- /dev/null +++ b/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "PowerHalWrapperHidlV1_0Test" + +#include <android/hardware/power/Boost.h> +#include <android/hardware/power/IPower.h> +#include <android/hardware/power/Mode.h> +#include <binder/IServiceManager.h> + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <powermanager/PowerHalWrapper.h> + +#include <utils/Log.h> + +using android::hardware::power::Boost; +using android::hardware::power::Mode; +using android::hardware::power::V1_0::Feature; +using android::hardware::power::V1_0::IPower; +using android::hardware::power::V1_0::PowerHint; + +using namespace android; +using namespace std::chrono_literals; +using namespace testing; + +// ------------------------------------------------------------------------------------------------- + +class MockIPowerV1_0 : public IPower { +public: + MOCK_METHOD(hardware::Return<void>, setInteractive, (bool interactive), (override)); + MOCK_METHOD(hardware::Return<void>, powerHint, (PowerHint hint, int32_t data), (override)); + MOCK_METHOD( + hardware::Return<void>, setFeature, (Feature feature, bool activate), (override)); + MOCK_METHOD( + hardware::Return<void>, getPlatformLowPowerStats, + (getPlatformLowPowerStats_cb _hidl_cb), (override)); +}; + +// ------------------------------------------------------------------------------------------------- + +class PowerHalWrapperHidlV1_0Test : public Test { +public: + void SetUp() override; + +protected: + std::unique_ptr<PowerHalWrapper> mWrapper = nullptr; + sp<StrictMock<MockIPowerV1_0>> mMockHal = nullptr; +}; + +// ------------------------------------------------------------------------------------------------- + +void PowerHalWrapperHidlV1_0Test::SetUp() { + mMockHal = new StrictMock<MockIPowerV1_0>(); + mWrapper = std::make_unique<HidlPowerHalWrapperV1_0>(mMockHal); + ASSERT_NE(mWrapper, nullptr); +} + +// ------------------------------------------------------------------------------------------------- + +TEST_F(PowerHalWrapperHidlV1_0Test, TestSetBoostSuccessful) { + EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::INTERACTION), Eq(1000))) + .Times(Exactly(1)); + + auto result = mWrapper->setBoost(Boost::INTERACTION, 1000); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); +} + +TEST_F(PowerHalWrapperHidlV1_0Test, TestSetBoostFailed) { + EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::INTERACTION), Eq(1000))) + .Times(Exactly(1)) + .WillRepeatedly([](PowerHint, int32_t) { + return hardware::Return<void>(hardware::Status::fromExceptionCode(-1)); + }); + + auto result = mWrapper->setBoost(Boost::INTERACTION, 1000); + ASSERT_EQ(PowerHalResult::FAILED, result); +} + +TEST_F(PowerHalWrapperHidlV1_0Test, TestSetBoostUnsupported) { + auto result = mWrapper->setBoost(Boost::CAMERA_LAUNCH, 10); + ASSERT_EQ(PowerHalResult::UNSUPPORTED, result); +} + +TEST_F(PowerHalWrapperHidlV1_0Test, TestSetModeSuccessful) { + { + InSequence seq; + EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), Eq(1))) + .Times(Exactly(1)); + EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LOW_POWER), Eq(0))) + .Times(Exactly(1)); + EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::SUSTAINED_PERFORMANCE), Eq(1))) + .Times(Exactly(1)); + EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::VR_MODE), Eq(0))) + .Times(Exactly(1)); + EXPECT_CALL(*mMockHal.get(), setInteractive(Eq(true))) + .Times(Exactly(1)); + EXPECT_CALL(*mMockHal.get(), + setFeature(Eq(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE), Eq(false))) + .Times(Exactly(1)); + } + + auto result = mWrapper->setMode(Mode::LAUNCH, true); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::LOW_POWER, false); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::SUSTAINED_PERFORMANCE, true); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::VR, false); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::INTERACTIVE, true); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::DOUBLE_TAP_TO_WAKE, false); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); +} + +TEST_F(PowerHalWrapperHidlV1_0Test, TestSetModeFailed) { + EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), Eq(1))) + .Times(Exactly(1)) + .WillRepeatedly([](PowerHint, int32_t) { + return hardware::Return<void>(hardware::Status::fromExceptionCode(-1)); + }); + + auto result = mWrapper->setMode(Mode::LAUNCH, 1); + ASSERT_EQ(PowerHalResult::FAILED, result); +} + +TEST_F(PowerHalWrapperHidlV1_0Test, TestSetModeIgnored) { + auto result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true); + ASSERT_EQ(PowerHalResult::UNSUPPORTED, result); +} diff --git a/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp b/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp new file mode 100644 index 0000000000..931c0d5011 --- /dev/null +++ b/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "PowerHalWrapperHidlV1_1Test" + +#include <android/hardware/power/1.1/IPower.h> +#include <android/hardware/power/Boost.h> +#include <android/hardware/power/IPower.h> +#include <android/hardware/power/Mode.h> +#include <binder/IServiceManager.h> + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <powermanager/PowerHalWrapper.h> + +#include <utils/Log.h> + +using android::hardware::power::Boost; +using android::hardware::power::Mode; +using android::hardware::power::V1_0::Feature; +using android::hardware::power::V1_0::PowerHint; +using IPowerV1_1 = android::hardware::power::V1_1::IPower; +using IPowerV1_0 = android::hardware::power::V1_0::IPower; + +using namespace android; +using namespace std::chrono_literals; +using namespace testing; + +// ------------------------------------------------------------------------------------------------- + +class MockIPowerV1_0 : public IPowerV1_0 { +public: + MOCK_METHOD(hardware::Return<void>, setInteractive, (bool interactive), (override)); + MOCK_METHOD(hardware::Return<void>, powerHint, (PowerHint hint, int32_t data), (override)); + MOCK_METHOD( + hardware::Return<void>, setFeature, (Feature feature, bool activate), (override)); + MOCK_METHOD( + hardware::Return<void>, getPlatformLowPowerStats, + (getPlatformLowPowerStats_cb _hidl_cb), (override)); +}; + +class MockIPowerV1_1 : public IPowerV1_1 { +public: + MOCK_METHOD(hardware::Return<void>, setInteractive, (bool interactive), (override)); + MOCK_METHOD(hardware::Return<void>, powerHint, (PowerHint hint, int32_t data), (override)); + MOCK_METHOD( + hardware::Return<void>, setFeature, (Feature feature, bool activate), (override)); + MOCK_METHOD( + hardware::Return<void>, getPlatformLowPowerStats, + (getPlatformLowPowerStats_cb _hidl_cb), (override)); + MOCK_METHOD( + hardware::Return<void>, powerHintAsync, (PowerHint hint, int32_t data), (override)); + MOCK_METHOD( + hardware::Return<void>, getSubsystemLowPowerStats, + (getSubsystemLowPowerStats_cb _hidl_cb), (override)); +}; + +// ------------------------------------------------------------------------------------------------- + +class PowerHalWrapperHidlV1_1Test : public Test { +public: + void SetUp() override; + +protected: + std::unique_ptr<PowerHalWrapper> mWrapper = nullptr; + sp<StrictMock<MockIPowerV1_0>> mMockHalV1_0 = nullptr; + sp<StrictMock<MockIPowerV1_1>> mMockHalV1_1 = nullptr; +}; + +// ------------------------------------------------------------------------------------------------- + +void PowerHalWrapperHidlV1_1Test::SetUp() { + mMockHalV1_0 = new StrictMock<MockIPowerV1_0>(); + mMockHalV1_1 = new StrictMock<MockIPowerV1_1>(); + mWrapper = std::make_unique<HidlPowerHalWrapperV1_1>(mMockHalV1_0, mMockHalV1_1); + ASSERT_NE(mWrapper, nullptr); +} + +// ------------------------------------------------------------------------------------------------- + +TEST_F(PowerHalWrapperHidlV1_1Test, TestSetBoostSuccessful) { + EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::INTERACTION), Eq(1000))) + .Times(Exactly(1)); + + auto result = mWrapper->setBoost(Boost::INTERACTION, 1000); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); +} + +TEST_F(PowerHalWrapperHidlV1_1Test, TestSetBoostFailed) { + EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::INTERACTION), Eq(1000))) + .Times(Exactly(1)) + .WillRepeatedly([](PowerHint, int32_t) { + return hardware::Return<void>(hardware::Status::fromExceptionCode(-1)); + }); + + auto result = mWrapper->setBoost(Boost::INTERACTION, 1000); + ASSERT_EQ(PowerHalResult::FAILED, result); +} + +TEST_F(PowerHalWrapperHidlV1_1Test, TestSetBoostUnsupported) { + auto result = mWrapper->setBoost(Boost::CAMERA_LAUNCH, 10); + ASSERT_EQ(PowerHalResult::UNSUPPORTED, result); +} + +TEST_F(PowerHalWrapperHidlV1_1Test, TestSetMode) { + { + InSequence seq; + EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::LAUNCH), Eq(1))) + .Times(Exactly(1)); + EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::LOW_POWER), Eq(0))) + .Times(Exactly(1)); + EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::SUSTAINED_PERFORMANCE), Eq(1))) + .Times(Exactly(1)); + EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::VR_MODE), Eq(0))) + .Times(Exactly(1)); + EXPECT_CALL(*mMockHalV1_0.get(), setInteractive(Eq(true))) + .Times(Exactly(1)); + EXPECT_CALL(*mMockHalV1_0.get(), + setFeature(Eq(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE), Eq(false))) + .Times(Exactly(1)); + } + + auto result = mWrapper->setMode(Mode::LAUNCH, true); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::LOW_POWER, false); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::SUSTAINED_PERFORMANCE, true); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::VR, false); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::INTERACTIVE, true); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::DOUBLE_TAP_TO_WAKE, false); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); +} + +TEST_F(PowerHalWrapperHidlV1_1Test, TestSetModeFailed) { + EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::LAUNCH), Eq(1))) + .Times(Exactly(1)) + .WillRepeatedly([](PowerHint, int32_t) { + return hardware::Return<void>(hardware::Status::fromExceptionCode(-1)); + }); + + auto result = mWrapper->setMode(Mode::LAUNCH, 1); + ASSERT_EQ(PowerHalResult::FAILED, result); +} + +TEST_F(PowerHalWrapperHidlV1_1Test, TestSetModeIgnored) { + auto result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true); + ASSERT_EQ(PowerHalResult::UNSUPPORTED, result); +} |