diff options
author | Daniel Erat <derat@google.com> | 2015-09-18 09:58:03 -0600 |
---|---|---|
committer | Daniel Erat <derat@google.com> | 2015-09-18 12:04:37 -0600 |
commit | cb57344ce792f41e58bc476840a82eba14b0fde9 (patch) | |
tree | d1cbf876d54cd2d953afba4dec454211917a0c4a | |
parent | 11ad82ee79a70d27788a725fb235029864569363 (diff) | |
download | nativepower-cb57344ce792f41e58bc476840a82eba14b0fde9.tar.gz |
Add libnativepower and nativepowerman.
Add the skeleton of a C++ library and daemon that can be
used for power management by Brillo.
Bug: 22122485
Change-Id: I3769ecc3e7b43efc3e03af4afada48d570f56ef9
-rw-r--r-- | Android.mk | 22 | ||||
-rw-r--r-- | MODULE_LICENSE_APACHE2 | 0 | ||||
-rw-r--r-- | NOTICE | 190 | ||||
-rw-r--r-- | README | 7 | ||||
-rw-r--r-- | client/Android.mk | 63 | ||||
-rw-r--r-- | client/wake_lock.cc | 86 | ||||
-rw-r--r-- | client/wake_lock_unittest.cc | 70 | ||||
-rw-r--r-- | daemon/Android.mk | 119 | ||||
-rw-r--r-- | daemon/BnPowerManager.cc | 72 | ||||
-rw-r--r-- | daemon/main.cc | 65 | ||||
-rw-r--r-- | daemon/power_manager.cc | 89 | ||||
-rw-r--r-- | daemon/power_manager.h | 78 | ||||
-rw-r--r-- | daemon/power_manager_stub.cc | 100 | ||||
-rw-r--r-- | daemon/power_manager_unittest.cc | 69 | ||||
-rw-r--r-- | daemon/wake_lock_manager.cc | 130 | ||||
-rw-r--r-- | daemon/wake_lock_manager.h | 92 | ||||
-rw-r--r-- | daemon/wake_lock_manager_stub.cc | 43 | ||||
-rw-r--r-- | daemon/wake_lock_manager_stub.h | 61 | ||||
-rw-r--r-- | daemon/wake_lock_manager_unittest.cc | 142 | ||||
-rw-r--r-- | example/Android.mk | 39 | ||||
-rw-r--r-- | example/power_example.cc | 48 | ||||
-rw-r--r-- | include/nativepower/BnPowerManager.h | 37 | ||||
-rw-r--r-- | include/nativepower/constants.h | 27 | ||||
-rw-r--r-- | include/nativepower/power_manager_stub.h | 87 | ||||
-rw-r--r-- | include/nativepower/wake_lock.h | 68 |
25 files changed, 1804 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..72394ad --- /dev/null +++ b/Android.mk @@ -0,0 +1,22 @@ +# +# Copyright (C) 2015 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. +# + +# libchromeos is only built for Linux, so this package is too. +ifeq ($(HOST_OS),linux) + +include $(call all-subdir-makefiles) + +endif # HOST_OS == linux diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/MODULE_LICENSE_APACHE2 @@ -0,0 +1,190 @@ + + Copyright (c) 2014-2015, 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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + @@ -0,0 +1,7 @@ +This directory contains a C++ implementation of power management for use by +Brillo: + + client/ - libnativepower, a client library for calling nativepowerman + daemon/ - nativepowerman, a daemon that performs power management + example/ - power_example, an example executable that uses libnativepower + include/ - exported header files diff --git a/client/Android.mk b/client/Android.mk new file mode 100644 index 0000000..e2225df --- /dev/null +++ b/client/Android.mk @@ -0,0 +1,63 @@ +# +# Copyright (C) 2015 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. +# + +LOCAL_PATH := $(call my-dir) + +libnativepower_CommonCFlags := -Wall -Werror -Wno-unused-parameter +libnativepower_CommonCFlags += -Wno-sign-promo # for libchrome +libnativepower_CommonCIncludes := $(LOCAL_PATH)/../include +libnativepower_CommonSharedLibraries := \ + libbinder \ + libbinderwrapper \ + libchrome \ + libchromeos \ + libpowermanager \ + libutils \ + +# libnativepower shared library +# ======================================================== + +include $(CLEAR_VARS) +LOCAL_MODULE := libnativepower +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := $(libnativepower_CommonCFlags) +LOCAL_C_INCLUDES := $(libnativepower_CommonCIncludes) +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../include +LOCAL_SHARED_LIBRARIES := $(libnativepower_CommonSharedLibraries) +LOCAL_SRC_FILES := \ + wake_lock.cc \ + +include $(BUILD_SHARED_LIBRARY) + +# libnativepower_tests executable +# ======================================================== + +include $(CLEAR_VARS) +LOCAL_MODULE := libnativepower_tests +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := $(libnativepower_CommonCFlags) +LOCAL_C_INCLUDES := $(libnativepower_CommonCIncludes) +LOCAL_STATIC_LIBRARIES := libgtest libBionicGtestMain +LOCAL_SHARED_LIBRARIES := \ + $(libnativepower_CommonSharedLibraries) \ + libbinderwrapper_test_support \ + libnativepower \ + libnativepower_test_support \ + +LOCAL_SRC_FILES := \ + wake_lock_unittest.cc \ + +include $(BUILD_NATIVE_TEST) diff --git a/client/wake_lock.cc b/client/wake_lock.cc new file mode 100644 index 0000000..98dcb0e --- /dev/null +++ b/client/wake_lock.cc @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2015 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 <nativepower/wake_lock.h> + +#include <base/bind.h> +#include <base/logging.h> +#include <binder/IBinder.h> +#include <binderwrapper/binder_wrapper.h> +#include <nativepower/constants.h> +#include <powermanager/PowerManager.h> + +namespace android { + +// static +std::unique_ptr<WakeLock> WakeLock::Create(const std::string& tag, + const std::string& package) { + std::unique_ptr<WakeLock> lock(new WakeLock(tag, package)); + if (!lock->Init()) + lock.reset(); + return lock; +} + +WakeLock::~WakeLock() { + if (power_manager_.get()) { + BinderWrapper::Get()->UnregisterForDeathNotifications( + IInterface::asBinder(power_manager_)); + status_t status = + power_manager_->releaseWakeLock(lock_binder_, 0 /* flags */); + if (status != OK) { + LOG(ERROR) << "Wake lock release request for \"" << tag_ << "\" failed " + << "with status " << status; + } + } +} + +WakeLock::WakeLock(const std::string& tag, const std::string& package) + : tag_(tag), + package_(package) {} + +bool WakeLock::Init() { + sp<IBinder> power_manager_binder = + BinderWrapper::Get()->GetService(kPowerManagerServiceName); + if (!power_manager_binder.get()) { + LOG(ERROR) << "Didn't get " << kPowerManagerServiceName << " service"; + return false; + } + + power_manager_ = interface_cast<IPowerManager>(power_manager_binder); + BinderWrapper::Get()->RegisterForDeathNotifications( + power_manager_binder, + base::Bind(&WakeLock::OnPowerManagerDied, base::Unretained(this))); + + lock_binder_ = BinderWrapper::Get()->CreateLocalBinder(); + status_t status = power_manager_->acquireWakeLock( + POWERMANAGER_PARTIAL_WAKE_LOCK, + lock_binder_, String16(tag_.c_str()), String16(package_.c_str())); + if (status != OK) { + LOG(ERROR) << "Wake lock acquire request for tag \"" << tag_ << "\" failed " + << "with status " << status; + power_manager_.clear(); + return false; + } + + return true; +} + +void WakeLock::OnPowerManagerDied() { + LOG(WARNING) << "Power manager died; lost wake lock for \"" << tag_ << "\""; + power_manager_.clear(); +} + +} // namespace android diff --git a/client/wake_lock_unittest.cc b/client/wake_lock_unittest.cc new file mode 100644 index 0000000..1221f1a --- /dev/null +++ b/client/wake_lock_unittest.cc @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2015 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 <memory> + +#include <base/macros.h> +#include <binder/Binder.h> +#include <binder/IBinder.h> +#include <binderwrapper/binder_test_base.h> +#include <binderwrapper/stub_binder_wrapper.h> +#include <nativepower/constants.h> +#include <nativepower/power_manager_stub.h> +#include <nativepower/wake_lock.h> + +namespace android { + +class WakeLockTest : public BinderTestBase { + public: + WakeLockTest() + : power_manager_(new PowerManagerStub()), + power_manager_binder_(power_manager_) { + binder_wrapper_->SetBinderForService(kPowerManagerServiceName, + power_manager_binder_); + } + ~WakeLockTest() override = default; + + protected: + PowerManagerStub* power_manager_; // Owned by |power_manager_binder_|. + sp<IBinder> power_manager_binder_; + + private: + DISALLOW_COPY_AND_ASSIGN(WakeLockTest); +}; + +TEST_F(WakeLockTest, CreateAndDestroy) { + std::unique_ptr<WakeLock> lock(WakeLock::Create("foo", "bar")); + ASSERT_EQ(1u, power_manager_->num_locks()); + ASSERT_EQ(1u, binder_wrapper()->local_binders().size()); + EXPECT_EQ( + PowerManagerStub::ConstructLockString("foo", "bar", -1), + power_manager_->GetLockString(binder_wrapper()->local_binders()[0])); + + lock.reset(); + EXPECT_EQ(0u, power_manager_->num_locks()); +} + +TEST_F(WakeLockTest, PowerManagerDeath) { + std::unique_ptr<WakeLock> lock(WakeLock::Create("foo", "bar")); + binder_wrapper()->NotifyAboutBinderDeath(power_manager_binder_); + + // Since the WakeLock was informed that the power manager died, it shouldn't + // try to release its lock on destruction. + lock.reset(); + EXPECT_EQ(1u, power_manager_->num_locks()); +} + +} // namespace android diff --git a/daemon/Android.mk b/daemon/Android.mk new file mode 100644 index 0000000..d8ad7b1 --- /dev/null +++ b/daemon/Android.mk @@ -0,0 +1,119 @@ +# +# Copyright (C) 2015 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. +# + +LOCAL_PATH := $(call my-dir) + +nativepowerman_CommonCFlags := -Wall -Werror -Wno-unused-parameter +nativepowerman_CommonCFlags += -Wno-sign-promo # for libchrome +nativepowerman_CommonCIncludes := $(LOCAL_PATH)/../include +nativepowerman_CommonSharedLibraries := \ + libbinder \ + libchrome \ + libpowermanager \ + libutils \ + +# nativepowerman executable +# ======================================================== + +include $(CLEAR_VARS) +# "nativepowermanager" would probably be a better name, but Android service +# names are limited to 16 characters. +LOCAL_MODULE := nativepowerman +LOCAL_REQUIRED_MODULES := init.nativepowerman.rc +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := $(nativepowerman_CommonCFlags) +LOCAL_STATIC_LIBRARIES := libnativepowerman +LOCAL_SHARED_LIBRARIES := \ + $(nativepowerman_CommonSharedLibraries) \ + libbinderwrapper \ + libchromeos \ + libchromeos-binder \ + +LOCAL_SRC_FILES := main.cc + +include $(BUILD_EXECUTABLE) + +# init.nativepowerman.rc script +# ======================================================== + +ifdef INITRC_TEMPLATE +include $(CLEAR_VARS) +LOCAL_MODULE := init.nativepowerman.rc +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(PRODUCT_OUT)/$(TARGET_COPY_OUT_INITRCD) + +include $(BUILD_SYSTEM)/base_rules.mk + +$(LOCAL_BUILT_MODULE): $(INITRC_TEMPLATE) + $(call generate-initrc-file,nativepowerman,,) +endif + +# libnativepowerman client library (for daemon and tests) +# ======================================================== + +include $(CLEAR_VARS) +LOCAL_MODULE := libnativepowerman +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := $(nativepowerman_CommonCFlags) +LOCAL_C_INCLUDES := $(nativepowerman_CommonCIncludes) external/gtest/include +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../include +LOCAL_SHARED_LIBRARIES := \ + $(nativepowerman_CommonSharedLibraries) \ + libbinderwrapper \ + libchromeos \ + +LOCAL_SRC_FILES := \ + BnPowerManager.cc \ + power_manager.cc \ + wake_lock_manager.cc \ + +include $(BUILD_STATIC_LIBRARY) + +# nativepowerman_tests executable +# ======================================================== + +include $(CLEAR_VARS) +LOCAL_MODULE := nativepowerman_tests +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := $(nativepowerman_CommonCFlags) +LOCAL_STATIC_LIBRARIES := libnativepowerman libgtest libBionicGtestMain +LOCAL_SHARED_LIBRARIES := \ + $(nativepowerman_CommonSharedLibraries) \ + libbinderwrapper \ + libbinderwrapper_test_support \ + +LOCAL_SRC_FILES := \ + power_manager_unittest.cc \ + wake_lock_manager_stub.cc \ + wake_lock_manager_unittest.cc \ + +include $(BUILD_NATIVE_TEST) + +# libnativepower_test_support shared library +# ======================================================== + +include $(CLEAR_VARS) +LOCAL_MODULE := libnativepower_test_support +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := $(nativepowerman_CommonCFlags) +LOCAL_C_INCLUDES := $(nativepowerman_CommonCIncludes) +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../include +LOCAL_SHARED_LIBRARIES := $(nativepowerman_CommonSharedLibraries) +LOCAL_SRC_FILES := \ + BnPowerManager.cc \ + power_manager_stub.cc \ + +include $(BUILD_SHARED_LIBRARY) diff --git a/daemon/BnPowerManager.cc b/daemon/BnPowerManager.cc new file mode 100644 index 0000000..ed6b9e1 --- /dev/null +++ b/daemon/BnPowerManager.cc @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 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 <nativepower/BnPowerManager.h> + +#include <binder/Parcel.h> + +namespace android { + +status_t BnPowerManager::onTransact(uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags) { + switch (code) { + case IPowerManager::ACQUIRE_WAKE_LOCK: { + // The parameter orders in IPowerManager.aidl and IPowerManager.h don't + // match. :-( (BpPowerManager in IPowerManager.cpp passes arguments in the + // order that the AIDL file describes and that we use here, though.) + CHECK_INTERFACE(IPowerManager, data, reply); + sp<IBinder> lock = data.readStrongBinder(); + int32_t flags = data.readInt32(); + String16 tag = data.readString16(); + String16 package_name = data.readString16(); + // Ignore work source and history. + return acquireWakeLock(flags, lock, tag, package_name); + } + case IPowerManager::ACQUIRE_WAKE_LOCK_UID: { + CHECK_INTERFACE(IPowerManager, data, reply); + sp<IBinder> lock = data.readStrongBinder(); + int32_t flags = data.readInt32(); + String16 tag = data.readString16(); + String16 package_name = data.readString16(); + int32_t uid = data.readInt32(); + return acquireWakeLockWithUid(flags, lock, tag, package_name, uid); + } + case IPowerManager::RELEASE_WAKE_LOCK: { + CHECK_INTERFACE(IPowerManager, data, reply); + sp<IBinder> lock = data.readStrongBinder(); + int32_t flags = data.readInt32(); + return releaseWakeLock(lock, flags); + } + case IPowerManager::UPDATE_WAKE_LOCK_UIDS: { + CHECK_INTERFACE(IPowerManager, data, reply); + sp<IBinder> lock = data.readStrongBinder(); + // TODO: There's no Parcel::readInt32Array(). Add one. + return updateWakeLockUids(lock, 0, nullptr); + } + case IPowerManager::POWER_HINT: { + CHECK_INTERFACE(IPowerManager, data, reply); + int32_t hint_id = data.readInt32(); + int32_t params = data.readInt32(); + return powerHint(hint_id, params); + } + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +} // namespace android diff --git a/daemon/main.cc b/daemon/main.cc new file mode 100644 index 0000000..0458441 --- /dev/null +++ b/daemon/main.cc @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 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 <sysexits.h> + +#include <base/logging.h> +#include <base/macros.h> +#include <binderwrapper/binder_wrapper.h> +#include <chromeos/binder_watcher.h> +#include <chromeos/daemons/daemon.h> +#include <chromeos/flag_helper.h> + +#include "power_manager.h" + +namespace { + +class PowerManagerDaemon : public chromeos::Daemon { + public: + PowerManagerDaemon() = default; + ~PowerManagerDaemon() override = default; + + private: + // chromeos::Daemon: + int OnInit() override { + int result = chromeos::Daemon::OnInit(); + if (result != EX_OK) + return result; + + android::BinderWrapper::Create(); + if (!binder_watcher_.Init()) + return EX_OSERR; + if (!power_manager_.Init()) + return EX_OSERR; + + LOG(INFO) << "Initialization complete"; + return EX_OK; + } + + chromeos::BinderWatcher binder_watcher_; + android::PowerManager power_manager_; + + DISALLOW_COPY_AND_ASSIGN(PowerManagerDaemon); +}; + +} // namespace + +int main(int argc, char *argv[]) { + // This also initializes base::CommandLine(), which is needed for logging. + chromeos::FlagHelper::Init(argc, argv, "Power management daemon"); + logging::InitLogging(logging::LoggingSettings()); + return PowerManagerDaemon().Run(); +} diff --git a/daemon/power_manager.cc b/daemon/power_manager.cc new file mode 100644 index 0000000..55dd799 --- /dev/null +++ b/daemon/power_manager.cc @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2015 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 "power_manager.h" + +#include <base/logging.h> +#include <binderwrapper/binder_wrapper.h> +#include <nativepower/constants.h> +#include <powermanager/IPowerManager.h> +#include <utils/Errors.h> +#include <utils/String8.h> + +namespace android { + +PowerManager::PowerManager() = default; + +PowerManager::~PowerManager() = default; + +bool PowerManager::Init() { + if (!wake_lock_manager_) { + wake_lock_manager_.reset(new WakeLockManager()); + if (!static_cast<WakeLockManager*>(wake_lock_manager_.get())->Init()) + return false; + } + + LOG(INFO) << "Registering with service manager as " + << kPowerManagerServiceName; + return BinderWrapper::Get()->RegisterService(kPowerManagerServiceName, this); +} + +status_t PowerManager::acquireWakeLock(int flags, + const sp<IBinder>& lock, + const String16& tag, + const String16& packageName, + bool isOneWay) { + return AddWakeLockRequest(lock, tag, packageName, -1) ? OK : UNKNOWN_ERROR; +} + +status_t PowerManager::acquireWakeLockWithUid(int flags, + const sp<IBinder>& lock, + const String16& tag, + const String16& packageName, + int uid, + bool isOneWay) { + return AddWakeLockRequest(lock, tag, packageName, uid) ? OK : UNKNOWN_ERROR; +} + +status_t PowerManager::releaseWakeLock(const sp<IBinder>& lock, + int flags, + bool isOneWay) { + return wake_lock_manager_->RemoveRequest(lock) ? OK : UNKNOWN_ERROR; +} + +status_t PowerManager::updateWakeLockUids(const sp<IBinder>& lock, + int len, + const int* uids, + bool isOneWay) { + NOTIMPLEMENTED() << "updateWakeLockUids: lock=" << lock.get() + << " len=" << len; + return OK; +} + +status_t PowerManager::powerHint(int hintId, int data) { + NOTIMPLEMENTED() << "powerHint: hintId=" << hintId << " data=" << data; + return OK; +} + +bool PowerManager::AddWakeLockRequest(const sp<IBinder>& lock, + const String16& tag, + const String16& packageName, + int uid) { + return wake_lock_manager_->AddRequest(lock, String8(tag).string(), + String8(packageName).string(), uid); +} + +} // namespace android diff --git a/daemon/power_manager.h b/daemon/power_manager.h new file mode 100644 index 0000000..98385b0 --- /dev/null +++ b/daemon/power_manager.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2015 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 SYSTEM_NATIVEPOWER_DAEMON_POWER_MANAGER_H_ +#define SYSTEM_NATIVEPOWER_DAEMON_POWER_MANAGER_H_ + +#include <memory> + +#include <base/macros.h> +#include <nativepower/BnPowerManager.h> + +#include "wake_lock_manager.h" + +namespace android { + +class PowerManager : public BnPowerManager { + public: + PowerManager(); + ~PowerManager() override; + + // Must be called before Init(). + void set_wake_lock_manager_for_testing( + std::unique_ptr<WakeLockManagerInterface> manager) { + wake_lock_manager_ = std::move(manager); + } + + // Initializes the object, returning true on success. + bool Init(); + + // BnPowerManager: + status_t acquireWakeLock(int flags, + const sp<IBinder>& lock, + const String16& tag, + const String16& packageName, + bool isOneWay=false) override; + status_t acquireWakeLockWithUid(int flags, + const sp<IBinder>& lock, + const String16& tag, + const String16& packageName, + int uid, + bool isOneWay=false) override; + status_t releaseWakeLock(const sp<IBinder>& lock, + int flags, + bool isOneWay=false) override; + status_t updateWakeLockUids(const sp<IBinder>& lock, + int len, + const int* uids, + bool isOneWay=false) override; + status_t powerHint(int hintId, int data) override; + + private: + // Helper method for acquireWakeLock*(). Returns true on success. + bool AddWakeLockRequest(const sp<IBinder>& lock, + const String16& tag, + const String16& packageName, + int uid); + + std::unique_ptr<WakeLockManagerInterface> wake_lock_manager_; + + DISALLOW_COPY_AND_ASSIGN(PowerManager); +}; + +} // namespace android + +#endif // SYSTEM_NATIVEPOWER_DAEMON_POWER_MANAGER_H_ diff --git a/daemon/power_manager_stub.cc b/daemon/power_manager_stub.cc new file mode 100644 index 0000000..40490d3 --- /dev/null +++ b/daemon/power_manager_stub.cc @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2015 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 <base/logging.h> +#include <base/strings/stringprintf.h> +#include <nativepower/power_manager_stub.h> +#include <utils/String8.h> + +namespace android { + +PowerManagerStub::LockInfo::LockInfo() : uid(-1) {} + +PowerManagerStub::LockInfo::LockInfo(const LockInfo& info) = default; + +PowerManagerStub::LockInfo::LockInfo(const std::string& tag, + const std::string& package, + int uid) + : tag(tag), + package(package), + uid(uid) {} + +// static +std::string PowerManagerStub::ConstructLockString(const std::string& tag, + const std::string& package, + int uid) { + return base::StringPrintf("%s,%s,%d", tag.c_str(), package.c_str(), uid); +} + +PowerManagerStub::PowerManagerStub() = default; + +PowerManagerStub::~PowerManagerStub() = default; + +std::string PowerManagerStub::GetLockString(const sp<IBinder>& binder) const { + const auto it = locks_.find(binder); + if (it == locks_.end()) + return std::string(); + + const LockInfo& info = it->second; + return ConstructLockString(info.tag, info.package, info.uid); +} + +status_t PowerManagerStub::acquireWakeLock(int flags, + const sp<IBinder>& lock, + const String16& tag, + const String16& packageName, + bool isOneWay) { + CHECK(!locks_.count(lock)) << "Got acquireWakeLock() request for " + << "already-registered binder " << lock.get(); + locks_[lock] = + LockInfo(String8(tag).string(), String8(packageName).string(), -1); + return OK; +} + +status_t PowerManagerStub::acquireWakeLockWithUid(int flags, + const sp<IBinder>& lock, + const String16& tag, + const String16& packageName, + int uid, + bool isOneWay) { + CHECK(!locks_.count(lock)) << "Got acquireWakeLockWithUid() request for " + << "already-registered binder " << lock.get(); + locks_[lock] = + LockInfo(String8(tag).string(), String8(packageName).string(), uid); + return OK; +} + +status_t PowerManagerStub::releaseWakeLock(const sp<IBinder>& lock, + int flags, + bool isOneWay) { + CHECK(locks_.count(lock)) << "Got releaseWakeLock() request for unregistered " + << "binder " << lock.get(); + locks_.erase(lock); + return OK; +} + +status_t PowerManagerStub::updateWakeLockUids(const sp<IBinder>& lock, + int len, + const int* uids, + bool isOneWay) { + return OK; +} + +status_t PowerManagerStub::powerHint(int hintId, int data) { + return OK; +} + +} // namespace android diff --git a/daemon/power_manager_unittest.cc b/daemon/power_manager_unittest.cc new file mode 100644 index 0000000..45c5bc6 --- /dev/null +++ b/daemon/power_manager_unittest.cc @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2015 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 <base/macros.h> +#include <binder/IBinder.h> +#include <binder/IInterface.h> +#include <binderwrapper/binder_test_base.h> +#include <binderwrapper/stub_binder_wrapper.h> +#include <nativepower/constants.h> +#include <powermanager/PowerManager.h> + +#include "power_manager.h" +#include "wake_lock_manager.h" +#include "wake_lock_manager_stub.h" + +namespace android { + +class PowerManagerTest : public BinderTestBase { + public: + PowerManagerTest() + : power_manager_(new PowerManager()), + wake_lock_manager_(new WakeLockManagerStub()) { + power_manager_->set_wake_lock_manager_for_testing( + std::unique_ptr<WakeLockManagerInterface>(wake_lock_manager_)); + CHECK(power_manager_->Init()); + } + ~PowerManagerTest() override = default; + + protected: + sp<PowerManager> power_manager_; + WakeLockManagerStub* wake_lock_manager_; // Owned by |power_manager_|. + + private: + DISALLOW_COPY_AND_ASSIGN(PowerManagerTest); +}; + +TEST_F(PowerManagerTest, RegisterService) { + EXPECT_EQ(power_manager_, + binder_wrapper()->GetRegisteredService(kPowerManagerServiceName)); +} + +TEST_F(PowerManagerTest, AcquireAndReleaseWakeLock) { + sp<BBinder> binder = binder_wrapper()->CreateLocalBinder(); + EXPECT_EQ(OK, + interface_cast<IPowerManager>(power_manager_)->acquireWakeLock( + 0, binder, String16(), String16())); + ASSERT_EQ(1u, wake_lock_manager_->request_binders().size()); + EXPECT_TRUE(wake_lock_manager_->has_request_binder(binder)); + + EXPECT_EQ(OK, + interface_cast<IPowerManager>(power_manager_)->releaseWakeLock( + binder, 0)); + EXPECT_TRUE(wake_lock_manager_->request_binders().empty()); +} + +} // namespace android diff --git a/daemon/wake_lock_manager.cc b/daemon/wake_lock_manager.cc new file mode 100644 index 0000000..3c875f6 --- /dev/null +++ b/daemon/wake_lock_manager.cc @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2015 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 "wake_lock_manager.h" + +#include <base/bind.h> +#include <base/files/file_util.h> +#include <base/format_macros.h> +#include <base/logging.h> +#include <base/strings/stringprintf.h> +#include <binder/IBinder.h> +#include <binderwrapper/binder_wrapper.h> + +namespace android { +namespace { + +// Paths to the sysfs lock and unlock files. +const char kLockPath[] = "/sys/power/wake_lock"; +const char kUnlockPath[] = "/sys/power/wake_unlock"; + +// Writes |data| to |path|, returning true on success or logging an error and +// returning false otherwise. +bool WriteToFile(const base::FilePath& path, const std::string& data) { + // This are sysfs "files" in real life, so it doesn't matter if we overwrite + // them or append to them, but appending makes it easier for tests to detect + // multiple writes when using real temporary files. + VLOG(1) << "Writing \"" << data << "\" to " << path.value(); + if (!base::AppendToFile(path, data.data(), data.size())) { + PLOG(ERROR) << "Failed to write \"" << data << "\" to " << path.value(); + return false; + } + return true; +} + +} // namespace + +const char WakeLockManager::kLockName[] = "nativepowerman"; + +WakeLockManager::Request::Request(const std::string& tag, + const std::string& package, + int uid) + : tag(tag), + package(package), + uid(uid) {} + +WakeLockManager::Request::Request(const Request& request) = default; + +WakeLockManager::Request::Request() : uid(0) {} + +WakeLockManager::WakeLockManager() + : lock_path_(kLockPath), + unlock_path_(kUnlockPath) {} + +WakeLockManager::~WakeLockManager() { + while (!requests_.empty()) + RemoveRequest(requests_.begin()->first); +} + +bool WakeLockManager::Init() { + if (!base::PathIsWritable(lock_path_) || + !base::PathIsWritable(unlock_path_)) { + LOG(ERROR) << lock_path_.value() << " and/or " << unlock_path_.value() + << " are not writable"; + return false; + } + return true; +} + +bool WakeLockManager::AddRequest(sp<IBinder> client_binder, + const std::string& tag, + const std::string& package, + int uid) { + const bool new_request = !requests_.count(client_binder); + LOG(INFO) << (new_request ? "Adding" : "Updating") << " request for binder " + << client_binder.get() << ": tag=\"" << tag << "\"" + << " package=\"" << package << "\" uid=" << uid; + + const bool first_request = requests_.empty(); + + if (new_request) { + if (!BinderWrapper::Get()->RegisterForDeathNotifications( + client_binder, + base::Bind(&WakeLockManager::HandleBinderDeath, + base::Unretained(this), client_binder))) { + return false; + } + } + requests_[client_binder] = Request(tag, package, uid); + + if (first_request && !WriteToFile(lock_path_, kLockName)) + return false; + + return true; +} + +bool WakeLockManager::RemoveRequest(sp<IBinder> client_binder) { + LOG(INFO) << "Removing request for binder " << client_binder.get(); + + if (!requests_.erase(client_binder)) { + LOG(WARNING) << "Ignoring removal request for unknown binder " + << client_binder.get(); + return false; + } + BinderWrapper::Get()->UnregisterForDeathNotifications(client_binder); + + if (requests_.empty() && !WriteToFile(unlock_path_, kLockName)) + return false; + + return true; +} + +void WakeLockManager::HandleBinderDeath(sp<IBinder> binder) { + LOG(INFO) << "Received death notification for binder " << binder.get(); + RemoveRequest(binder); +} + +} // namespace android diff --git a/daemon/wake_lock_manager.h b/daemon/wake_lock_manager.h new file mode 100644 index 0000000..471ad10 --- /dev/null +++ b/daemon/wake_lock_manager.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2015 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 SYSTEM_NATIVEPOWER_DAEMON_WAKE_LOCK_MANAGER_H_ +#define SYSTEM_NATIVEPOWER_DAEMON_WAKE_LOCK_MANAGER_H_ + +#include <map> +#include <string> + +#include <base/files/file_path.h> +#include <base/macros.h> +#include <base/time/time.h> +#include <utils/StrongPointer.h> + +namespace android { + +class IBinder; + +class WakeLockManagerInterface { + public: + WakeLockManagerInterface() {} + virtual ~WakeLockManagerInterface() {} + + virtual bool AddRequest(sp<IBinder> client_binder, + const std::string& tag, + const std::string& package, + int uid) = 0; + virtual bool RemoveRequest(sp<IBinder> client_binder) = 0; +}; + +class WakeLockManager : public WakeLockManagerInterface { + public: + // Name of the kernel wake lock created by this class. + static const char kLockName[]; + + WakeLockManager(); + ~WakeLockManager() override; + + void set_paths_for_testing(const base::FilePath& lock_path, + const base::FilePath& unlock_path) { + lock_path_ = lock_path; + unlock_path_ = unlock_path; + } + + bool Init(); + + // WakeLockManagerInterface: + bool AddRequest(sp<IBinder> client_binder, + const std::string& tag, + const std::string& package, + int uid) override; + bool RemoveRequest(sp<IBinder> client_binder) override; + + private: + // Information about a request from a client. + struct Request { + Request(const std::string& tag, const std::string& package, int uid); + Request(const Request& request); + Request(); + + std::string tag; + std::string package; + int uid; + }; + + void HandleBinderDeath(sp<IBinder> binder); + + base::FilePath lock_path_; + base::FilePath unlock_path_; + + // Currently-active requests, keyed by client binders. + std::map<sp<IBinder>, Request> requests_; + + DISALLOW_COPY_AND_ASSIGN(WakeLockManager); +}; + +} // namespace android + +#endif // SYSTEM_NATIVEPOWER_DAEMON_WAKE_LOCK_MANAGER_H_ diff --git a/daemon/wake_lock_manager_stub.cc b/daemon/wake_lock_manager_stub.cc new file mode 100644 index 0000000..da7dc5e --- /dev/null +++ b/daemon/wake_lock_manager_stub.cc @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015 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 "wake_lock_manager_stub.h" + +#include <binder/IBinder.h> + +namespace android { + +WakeLockManagerStub::WakeLockManagerStub() = default; + +WakeLockManagerStub::~WakeLockManagerStub() = default; + +bool WakeLockManagerStub::AddRequest(sp<IBinder> client_binder, + const std::string& tag, + const std::string& package, + int uid) { + request_binders_.insert(client_binder); + return true; +} + +bool WakeLockManagerStub::RemoveRequest(sp<IBinder> client_binder) { + if (!request_binders_.count(client_binder)) + return false; + + request_binders_.erase(client_binder); + return true; +} + +} // namespace android diff --git a/daemon/wake_lock_manager_stub.h b/daemon/wake_lock_manager_stub.h new file mode 100644 index 0000000..3b73749 --- /dev/null +++ b/daemon/wake_lock_manager_stub.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2015 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 SYSTEM_NATIVEPOWER_DAEMON_WAKE_LOCK_MANAGER_STUB_H_ +#define SYSTEM_NATIVEPOWER_DAEMON_WAKE_LOCK_MANAGER_STUB_H_ + +#include <set> +#include <string> + +#include <base/macros.h> +#include <utils/StrongPointer.h> + +#include "wake_lock_manager.h" + +namespace android { + +class IBinder; + +// Stub implementation used by tests. +class WakeLockManagerStub : public WakeLockManagerInterface { + public: + using BinderSet = std::set<sp<IBinder>>; + + WakeLockManagerStub(); + ~WakeLockManagerStub() override; + + const BinderSet& request_binders() const { return request_binders_; } + bool has_request_binder(const sp<IBinder>& binder) const { + return request_binders_.count(binder); + } + + // WakeLockManagerInterface: + bool AddRequest(sp<IBinder> client_binder, + const std::string& tag, + const std::string& package, + int uid) override; + bool RemoveRequest(sp<IBinder> client_binder) override; + + private: + // Binders passed to AddRequest() for currently-active requests. + BinderSet request_binders_; + + DISALLOW_COPY_AND_ASSIGN(WakeLockManagerStub); +}; + +} // namespace android + +#endif // SYSTEM_NATIVEPOWER_DAEMON_WAKE_LOCK_MANAGER_STUB_H_ diff --git a/daemon/wake_lock_manager_unittest.cc b/daemon/wake_lock_manager_unittest.cc new file mode 100644 index 0000000..887b564 --- /dev/null +++ b/daemon/wake_lock_manager_unittest.cc @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2015 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 <base/files/file_path.h> +#include <base/files/file_util.h> +#include <base/files/scoped_temp_dir.h> +#include <base/logging.h> +#include <base/macros.h> +#include <binder/IBinder.h> +#include <binderwrapper/binder_test_base.h> +#include <binderwrapper/stub_binder_wrapper.h> + +#include "wake_lock_manager.h" + +namespace android { + +class WakeLockManagerTest : public BinderTestBase { + public: + WakeLockManagerTest() { + CHECK(temp_dir_.CreateUniqueTempDir()); + lock_path_ = temp_dir_.path().Append("lock"); + unlock_path_ = temp_dir_.path().Append("unlock"); + ClearFiles(); + + manager_.set_paths_for_testing(lock_path_, unlock_path_); + CHECK(manager_.Init()); + } + ~WakeLockManagerTest() override = default; + + protected: + // Returns the contents of |path|. + std::string ReadFile(const base::FilePath& path) const { + std::string value; + CHECK(base::ReadFileToString(path, &value)); + return value; + } + + // Clears |lock_path_| and |unlock_path_|. + void ClearFiles() { + CHECK(base::WriteFile(lock_path_, "", 0) == 0); + CHECK(base::WriteFile(unlock_path_, "", 0) == 0); + } + + base::ScopedTempDir temp_dir_; + + // Files within |temp_dir_| simulating /sys/power/wake_lock and wake_unlock. + base::FilePath lock_path_; + base::FilePath unlock_path_; + + WakeLockManager manager_; + + private: + DISALLOW_COPY_AND_ASSIGN(WakeLockManagerTest); +}; + +TEST_F(WakeLockManagerTest, AddAndRemoveRequests) { + // A kernel wake lock should be created for the first request. + sp<BBinder> binder1 = binder_wrapper()->CreateLocalBinder(); + EXPECT_TRUE(manager_.AddRequest(binder1, "1", "1", -1)); + EXPECT_EQ(WakeLockManager::kLockName, ReadFile(lock_path_)); + EXPECT_EQ("", ReadFile(unlock_path_)); + + // Nothing should happen when a second request is made. + ClearFiles(); + sp<BBinder> binder2 = binder_wrapper()->CreateLocalBinder(); + EXPECT_TRUE(manager_.AddRequest(binder2, "2", "2", -1)); + EXPECT_EQ("", ReadFile(lock_path_)); + EXPECT_EQ("", ReadFile(unlock_path_)); + + // The wake lock should still be held after the first request is withdrawn. + ClearFiles(); + EXPECT_TRUE(manager_.RemoveRequest(binder1)); + EXPECT_EQ("", ReadFile(lock_path_)); + EXPECT_EQ("", ReadFile(unlock_path_)); + + // When there are no more requests, the wake lock should be released. + ClearFiles(); + EXPECT_TRUE(manager_.RemoveRequest(binder2)); + EXPECT_EQ("", ReadFile(lock_path_)); + EXPECT_EQ(WakeLockManager::kLockName, ReadFile(unlock_path_)); +} + +TEST_F(WakeLockManagerTest, DuplicateRequest) { + sp<BBinder> binder = binder_wrapper()->CreateLocalBinder(); + EXPECT_TRUE(manager_.AddRequest(binder, "foo", "bar", -1)); + EXPECT_EQ(WakeLockManager::kLockName, ReadFile(lock_path_)); + EXPECT_EQ("", ReadFile(unlock_path_)); + + // Send a second request using the same binder and check a new wake lock isn't + // created. + ClearFiles(); + EXPECT_TRUE(manager_.AddRequest(binder, "a", "b", -1)); + EXPECT_EQ("", ReadFile(lock_path_)); + EXPECT_EQ("", ReadFile(unlock_path_)); + + ClearFiles(); + EXPECT_TRUE(manager_.RemoveRequest(binder)); + EXPECT_EQ("", ReadFile(lock_path_)); + EXPECT_EQ(WakeLockManager::kLockName, ReadFile(unlock_path_)); +} + +TEST_F(WakeLockManagerTest, InvalidRemoval) { + // Trying to remove an unknown binder should fail and not do anything. + sp<BBinder> binder = binder_wrapper()->CreateLocalBinder(); + EXPECT_FALSE(manager_.RemoveRequest(binder)); + EXPECT_EQ("", ReadFile(lock_path_)); + EXPECT_EQ("", ReadFile(unlock_path_)); +} + +TEST_F(WakeLockManagerTest, BinderDeath) { + sp<BBinder> binder = binder_wrapper()->CreateLocalBinder(); + EXPECT_TRUE(manager_.AddRequest(binder, "foo", "bar", -1)); + EXPECT_EQ(WakeLockManager::kLockName, ReadFile(lock_path_)); + EXPECT_EQ("", ReadFile(unlock_path_)); + + // If the binder dies, the wake lock should be released. + ClearFiles(); + binder_wrapper()->NotifyAboutBinderDeath(binder); + EXPECT_EQ("", ReadFile(lock_path_)); + EXPECT_EQ(WakeLockManager::kLockName, ReadFile(unlock_path_)); + + // Check that a new request can be created using the same binder. + ClearFiles(); + EXPECT_TRUE(manager_.AddRequest(binder, "foo", "bar", -1)); + EXPECT_EQ(WakeLockManager::kLockName, ReadFile(lock_path_)); + EXPECT_EQ("", ReadFile(unlock_path_)); +} + +} // namespace android diff --git a/example/Android.mk b/example/Android.mk new file mode 100644 index 0000000..19936e5 --- /dev/null +++ b/example/Android.mk @@ -0,0 +1,39 @@ +# +# Copyright (C) 2015 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. +# + +LOCAL_PATH := $(call my-dir) + +# power_example executable +# ======================================================== + +include $(CLEAR_VARS) +LOCAL_MODULE := power_example +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter +LOCAL_CFLAGS += -Wno-sign-promo # for libchrome +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libbinderwrapper \ + libchrome \ + libchromeos \ + libnativepower \ + libpowermanager \ + libutils \ + +LOCAL_SRC_FILES := \ + power_example.cc \ + +include $(BUILD_EXECUTABLE) diff --git a/example/power_example.cc b/example/power_example.cc new file mode 100644 index 0000000..0ad9138 --- /dev/null +++ b/example/power_example.cc @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015 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 <unistd.h> + +#include <memory> + +#include <base/at_exit.h> +#include <base/logging.h> +#include <base/message_loop/message_loop.h> +#include <binderwrapper/binder_wrapper.h> +#include <chromeos/flag_helper.h> +#include <nativepower/wake_lock.h> + +using android::BinderWrapper; +using android::WakeLock; + +int main(int argc, char *argv[]) { + DEFINE_int32(sleep_sec, 5, "Number of seconds to sleep"); + + chromeos::FlagHelper::Init(argc, argv, "Example power-management client."); + logging::InitLogging(logging::LoggingSettings()); + base::AtExitManager at_exit; + base::MessageLoopForIO loop; + BinderWrapper::Create(); + + LOG(INFO) << "Creating wake lock"; + std::unique_ptr<WakeLock> lock(WakeLock::Create("power_example", "power")); + + LOG(INFO) << "Sleeping for " << FLAGS_sleep_sec << " seconds"; + sleep(FLAGS_sleep_sec); + + LOG(INFO) << "Exiting"; + return 0; +} diff --git a/include/nativepower/BnPowerManager.h b/include/nativepower/BnPowerManager.h new file mode 100644 index 0000000..db14ef3 --- /dev/null +++ b/include/nativepower/BnPowerManager.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015 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 SYSTEM_NATIVEPOWER_INCLUDE_NATIVEPOWER_BN_POWER_MANAGER_H_ +#define SYSTEM_NATIVEPOWER_INCLUDE_NATIVEPOWER_BN_POWER_MANAGER_H_ + +#include <binder/IInterface.h> +#include <powermanager/IPowerManager.h> + +namespace android { + +// Receiver-side binder implementation. +class BnPowerManager : public BnInterface<IPowerManager> { +public: + // BnInterface: + status_t onTransact(uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags=0) override; +}; + +} // namespace android + +#endif // SYSTEM_NATIVEPOWER_INCLUDE_NATIVEPOWER_BN_POWER_MANAGER_H_ diff --git a/include/nativepower/constants.h b/include/nativepower/constants.h new file mode 100644 index 0000000..ddeb3d7 --- /dev/null +++ b/include/nativepower/constants.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2015 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 SYSTEM_NATIVEPOWER_INCLUDE_NATIVEPOWER_CONSTANTS_H_ +#define SYSTEM_NATIVEPOWER_INCLUDE_NATIVEPOWER_CONSTANTS_H_ + +namespace android { + +// Name used to register the power manager with the service manager. +const char kPowerManagerServiceName[] = "power"; + +} // namespace android + +#endif // SYSTEM_NATIVEPOWER_INCLUDE_NATIVEPOWER_CONSTANTS_H_ diff --git a/include/nativepower/power_manager_stub.h b/include/nativepower/power_manager_stub.h new file mode 100644 index 0000000..ab303c2 --- /dev/null +++ b/include/nativepower/power_manager_stub.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2015 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 <map> +#include <string> + +#include <base/macros.h> +#include <nativepower/BnPowerManager.h> + +namespace android { + +// Stub implementation of BnPowerManager for use in tests. +class PowerManagerStub : public BnPowerManager { + public: + PowerManagerStub(); + ~PowerManagerStub() override; + + // Constructs a string that can be compared with one returned by + // GetLockString(). + static std::string ConstructLockString(const std::string& tag, + const std::string& package, + int uid); + + size_t num_locks() const { return locks_.size(); } + + // Returns a string describing the lock registered for |binder|, or an empty + // string if no lock is present. + std::string GetLockString(const sp<IBinder>& binder) const; + + // BnPowerManager: + status_t acquireWakeLock(int flags, + const sp<IBinder>& lock, + const String16& tag, + const String16& packageName, + bool isOneWay=false) override; + status_t acquireWakeLockWithUid(int flags, + const sp<IBinder>& lock, + const String16& tag, + const String16& packageName, + int uid, + bool isOneWay=false) override; + status_t releaseWakeLock(const sp<IBinder>& lock, + int flags, + bool isOneWay=false) override; + status_t updateWakeLockUids(const sp<IBinder>& lock, + int len, + const int* uids, + bool isOneWay=false) override; + status_t powerHint(int hintId, int data) override; + + private: + // Contains information passed to acquireWakeLock() or + // acquireWakeLockWithUid(). + struct LockInfo { + LockInfo(); + LockInfo(const LockInfo& info); + LockInfo(const std::string& tag, + const std::string& package, + int uid); + + std::string tag; + std::string package; + + // -1 if acquireWakeLock() was used. + int uid; + }; + + using LockInfoMap = std::map<sp<IBinder>, LockInfo>; + LockInfoMap locks_; + + DISALLOW_COPY_AND_ASSIGN(PowerManagerStub); +}; + +} // namespace android diff --git a/include/nativepower/wake_lock.h b/include/nativepower/wake_lock.h new file mode 100644 index 0000000..6fc0782 --- /dev/null +++ b/include/nativepower/wake_lock.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2015 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 SYSTEM_NATIVEPOWER_INCLUDE_NATIVEPOWER_WAKE_LOCK_H_ +#define SYSTEM_NATIVEPOWER_INCLUDE_NATIVEPOWER_WAKE_LOCK_H_ + +#include <memory> +#include <string> + +#include <base/macros.h> +#include <powermanager/IPowerManager.h> +#include <utils/StrongPointer.h> + +namespace android { + +class IBinder; + +// RAII-style object that prevents the system from suspending. +// +// android::BinderWrapper must be initialized before constructing this class. +class WakeLock { + public: + // Creates and returns a wake lock identified by |tag| and |package|. + // An empty pointer is returned on failure (e.g. due to issues communicating + // with the power manager). + static std::unique_ptr<WakeLock> Create(const std::string& tag, + const std::string& package); + + ~WakeLock(); + + private: + // Called by Create(). + WakeLock(const std::string& tag, const std::string& package); + + // Initializes the object and returns true on success. Called by Create(). + bool Init(); + + // Called by |death_recipient_| in response to |power_manager_| dying. + void OnPowerManagerDied(); + + std::string tag_; + std::string package_; + + // Interface for communicating with the power manager. + sp<IPowerManager> power_manager_; + + // Locally-created binder passed to the power manager. + sp<IBinder> lock_binder_; + + DISALLOW_COPY_AND_ASSIGN(WakeLock); +}; + +} // namespace android + +#endif // SYSTEM_NATIVEPOWER_INCLUDE_NATIVEPOWER_WAKE_LOCK_H_ |