diff options
author | 2020-03-30 20:17:42 +0100 | |
---|---|---|
committer | 2020-04-19 11:22:53 +0100 | |
commit | c86c1d26220a7a69d3b0f7b9e97a6e5b95e6f40b (patch) | |
tree | bc7f44c7ff70faa50c23347d5088ccaff37ce626 | |
parent | e24802725c3b5315a458e283ab7e4088bf4c8a07 (diff) |
Create loader for Power HAL services
Move logic to load underlying Power HAL services to a static class in
services/powermanager, with tests. This can now be reused by
BatteryStatsService and PowerManagerService, removing the dependency
between them.
Bug: 150878220
Test: atest powermanager_test
Change-Id: I52eec130811d49111526f3e152faf4302518c5a8
-rw-r--r-- | include/powermanager/PowerHalLoader.h | 52 | ||||
-rw-r--r-- | services/powermanager/Android.bp | 1 | ||||
-rw-r--r-- | services/powermanager/PowerHalLoader.cpp | 94 | ||||
-rw-r--r-- | services/powermanager/tests/Android.bp | 2 | ||||
-rw-r--r-- | services/powermanager/tests/PowerHalLoaderTest.cpp | 113 |
5 files changed, 262 insertions, 0 deletions
diff --git a/include/powermanager/PowerHalLoader.h b/include/powermanager/PowerHalLoader.h new file mode 100644 index 0000000000..487b95b298 --- /dev/null +++ b/include/powermanager/PowerHalLoader.h @@ -0,0 +1,52 @@ +/* + * 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_POWERHALLOADER_H +#define ANDROID_POWERHALLOADER_H + +#include <android-base/thread_annotations.h> + +#include <android/hardware/power/1.1/IPower.h> +#include <android/hardware/power/IPower.h> + +using IPowerV1_0 = android::hardware::power::V1_0::IPower; +using IPowerV1_1 = android::hardware::power::V1_1::IPower; +using IPowerAidl = android::hardware::power::IPower; + +namespace android { + +// Loads available Power HAL services. +class PowerHalLoader { +public: + static void unloadAll(); + static sp<IPowerAidl> loadAidl(); + static sp<IPowerV1_0> loadHidlV1_0(); + static sp<IPowerV1_1> loadHidlV1_1(); + +private: + static std::mutex gHalMutex; + static sp<IPowerAidl> gHalAidl GUARDED_BY(gHalMutex); + static sp<IPowerV1_0> gHalHidlV1_0 GUARDED_BY(gHalMutex); + static sp<IPowerV1_1> gHalHidlV1_1 GUARDED_BY(gHalMutex); + + static sp<IPowerV1_0> loadHidlV1_0Locked() EXCLUSIVE_LOCKS_REQUIRED(gHalMutex); + + PowerHalLoader() = default; +}; + +} // namespace android + +#endif // ANDROID_POWERHALLOADER_H diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp index cff4a029e6..eaf7fa8253 100644 --- a/services/powermanager/Android.bp +++ b/services/powermanager/Android.bp @@ -4,6 +4,7 @@ cc_library_shared { srcs: [ "BatterySaverPolicyConfig.cpp", "CoolingDevice.cpp", + "PowerHalLoader.cpp", "PowerHalWrapper.cpp", "PowerSaveState.cpp", "Temperature.cpp", diff --git a/services/powermanager/PowerHalLoader.cpp b/services/powermanager/PowerHalLoader.cpp new file mode 100644 index 0000000000..3ae538447b --- /dev/null +++ b/services/powermanager/PowerHalLoader.cpp @@ -0,0 +1,94 @@ +/* + * 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 "PowerHalLoader" + +#include <android/hardware/power/1.1/IPower.h> +#include <android/hardware/power/IPower.h> +#include <binder/IServiceManager.h> +#include <hardware/power.h> +#include <hardware_legacy/power.h> + +#include <powermanager/PowerHalLoader.h> + +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 { + +// ------------------------------------------------------------------------------------------------- + +template <typename T, typename F> +sp<T> loadHal(bool& exists, sp<T>& hal, F& loadFn, const char* halName) { + if (!exists) { + return nullptr; + } + if (hal) { + return hal; + } + hal = loadFn(); + if (hal) { + ALOGV("Successfully connected to Power HAL %s service.", halName); + } else { + ALOGV("Power HAL %s service not available.", halName); + exists = false; + } + return hal; +} + +// ------------------------------------------------------------------------------------------------- + +std::mutex PowerHalLoader::gHalMutex; +sp<IPowerAidl> PowerHalLoader::gHalAidl = nullptr; +sp<IPowerV1_0> PowerHalLoader::gHalHidlV1_0 = nullptr; +sp<IPowerV1_1> PowerHalLoader::gHalHidlV1_1 = nullptr; + +void PowerHalLoader::unloadAll() { + std::lock_guard<std::mutex> lock(gHalMutex); + gHalAidl = nullptr; + gHalHidlV1_0 = nullptr; + gHalHidlV1_1 = nullptr; +} + +sp<IPowerAidl> PowerHalLoader::loadAidl() { + std::lock_guard<std::mutex> lock(gHalMutex); + static bool gHalExists = true; + static auto loadFn = []() { return waitForVintfService<IPowerAidl>(); }; + return loadHal<IPowerAidl>(gHalExists, gHalAidl, loadFn, "AIDL"); +} + +sp<IPowerV1_0> PowerHalLoader::loadHidlV1_0() { + std::lock_guard<std::mutex> lock(gHalMutex); + return loadHidlV1_0Locked(); +} + +sp<IPowerV1_1> PowerHalLoader::loadHidlV1_1() { + std::lock_guard<std::mutex> lock(gHalMutex); + static bool gHalExists = true; + static auto loadFn = []() { return IPowerV1_1::castFrom(loadHidlV1_0Locked()); }; + return loadHal<IPowerV1_1>(gHalExists, gHalHidlV1_1, loadFn, "HIDL v1.1"); +} + +sp<IPowerV1_0> PowerHalLoader::loadHidlV1_0Locked() { + static bool gHalExists = true; + static auto loadFn = []() { return IPowerV1_0::getService(); }; + return loadHal<IPowerV1_0>(gHalExists, gHalHidlV1_0, loadFn, "HIDL v1.0"); +} + +// ------------------------------------------------------------------------------------------------- + +} // namespace android diff --git a/services/powermanager/tests/Android.bp b/services/powermanager/tests/Android.bp index 65cde03070..1cf170e059 100644 --- a/services/powermanager/tests/Android.bp +++ b/services/powermanager/tests/Android.bp @@ -12,10 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. + cc_test { name: "powermanager_test", test_suites: ["device-tests"], srcs: [ + "PowerHalLoaderTest.cpp", "PowerHalWrapperAidlTest.cpp", "PowerHalWrapperHidlV1_0Test.cpp", "PowerHalWrapperHidlV1_1Test.cpp", diff --git a/services/powermanager/tests/PowerHalLoaderTest.cpp b/services/powermanager/tests/PowerHalLoaderTest.cpp new file mode 100644 index 0000000000..2310a72318 --- /dev/null +++ b/services/powermanager/tests/PowerHalLoaderTest.cpp @@ -0,0 +1,113 @@ +/* + * 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 "PowerHalLoaderTest" + +#include <android-base/logging.h> +#include <android/hardware/power/1.1/IPower.h> +#include <android/hardware/power/IPower.h> + +#include <future> +#include <gtest/gtest.h> + +#include <powermanager/PowerHalLoader.h> + +using IPowerV1_0 = android::hardware::power::V1_0::IPower; +using IPowerV1_1 = android::hardware::power::V1_1::IPower; +using IPowerAidl = android::hardware::power::IPower; + +using namespace android; + +// ------------------------------------------------------------------------------------------------- + +template <typename T> +sp<T> loadHal(); + +template <> +sp<IPowerAidl> loadHal<IPowerAidl>() { + return PowerHalLoader::loadAidl(); +} + +template <> +sp<IPowerV1_0> loadHal<IPowerV1_0>() { + return PowerHalLoader::loadHidlV1_0(); +} + +template <> +sp<IPowerV1_1> loadHal<IPowerV1_1>() { + return PowerHalLoader::loadHidlV1_1(); +} + +// ------------------------------------------------------------------------------------------------- + +template <typename T> +class PowerHalLoaderTest : public testing::Test { +public: + sp<T> load() { + return ::loadHal<T>(); + } + void unload() { + PowerHalLoader::unloadAll(); + } +}; + +// ------------------------------------------------------------------------------------------------- + +typedef ::testing::Types<IPowerAidl, IPowerV1_0, IPowerV1_1> PowerHalTypes; +TYPED_TEST_SUITE(PowerHalLoaderTest, PowerHalTypes); + +TYPED_TEST(PowerHalLoaderTest, TestLoadsOnlyOnce) { + sp<TypeParam> firstHal = this->load(); + if (firstHal == nullptr) { + ALOGE("Power HAL not available. Skipping test."); + return; + } + sp<TypeParam> secondHal = this->load(); + ASSERT_EQ(firstHal, secondHal); +} + +TYPED_TEST(PowerHalLoaderTest, TestUnload) { + sp<TypeParam> firstHal = this->load(); + if (firstHal == nullptr) { + ALOGE("Power HAL not available. Skipping test."); + return; + } + this->unload(); + sp<TypeParam> secondHal = this->load(); + ASSERT_NE(secondHal, nullptr); + ASSERT_NE(firstHal, secondHal); +} + +TYPED_TEST(PowerHalLoaderTest, TestLoadMultiThreadLoadsOnlyOnce) { + std::vector<std::future<sp<TypeParam>>> futures; + for (int i = 0; i < 10; i++) { + futures.push_back( + std::async(std::launch::async, &PowerHalLoaderTest<TypeParam>::load, this)); + } + + futures[0].wait(); + sp<TypeParam> firstHal = futures[0].get(); + if (firstHal == nullptr) { + ALOGE("Power HAL not available. Skipping test."); + return; + } + + for (int i = 1; i < 10; i++) { + futures[i].wait(); + sp<TypeParam> currentHal = futures[i].get(); + ASSERT_EQ(firstHal, currentHal); + } +} |