Project import
diff --git a/nativepower/Android.mk b/nativepower/Android.mk
new file mode 100644
index 0000000..178cb8a
--- /dev/null
+++ b/nativepower/Android.mk
@@ -0,0 +1,17 @@
+#
+# 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 $(call all-subdir-makefiles)
diff --git a/nativepower/MODULE_LICENSE_APACHE2 b/nativepower/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/nativepower/MODULE_LICENSE_APACHE2
diff --git a/nativepower/NOTICE b/nativepower/NOTICE
new file mode 100644
index 0000000..a849a94
--- /dev/null
+++ b/nativepower/NOTICE
@@ -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
+
diff --git a/nativepower/README b/nativepower/README
new file mode 100644
index 0000000..bf8a5c7
--- /dev/null
+++ b/nativepower/README
@@ -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/nativepower/client/Android.mk b/nativepower/client/Android.mk
new file mode 100644
index 0000000..af2f50f
--- /dev/null
+++ b/nativepower/client/Android.mk
@@ -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.
+#
+
+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 \
+ libbrillo \
+ libchrome \
+ 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 := \
+ power_manager_client.cc \
+ 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 := \
+ power_manager_client_unittest.cc \
+ wake_lock_unittest.cc \
+
+include $(BUILD_NATIVE_TEST)
diff --git a/nativepower/client/power_manager_client.cc b/nativepower/client/power_manager_client.cc
new file mode 100644
index 0000000..20c437a
--- /dev/null
+++ b/nativepower/client/power_manager_client.cc
@@ -0,0 +1,140 @@
+/*
+ * 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/power_manager_client.h>
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <binder/IBinder.h>
+#include <binderwrapper/binder_wrapper.h>
+#include <nativepower/constants.h>
+#include <nativepower/wake_lock.h>
+#include <powermanager/PowerManager.h>
+
+namespace android {
+namespace {
+
+// Returns the string corresponding to |reason|. Values are hardcoded in
+// core/java/android/os/PowerManager.java.
+String16 ShutdownReasonToString16(ShutdownReason reason) {
+ switch (reason) {
+ case ShutdownReason::DEFAULT:
+ return String16();
+ case ShutdownReason::USER_REQUESTED:
+ return String16(kShutdownReasonUserRequested);
+ default:
+ LOG(ERROR) << "Unknown shutdown reason " << static_cast<int>(reason);
+ return String16();
+ }
+}
+
+// Returns the string corresponding to |reason|. Values are hardcoded in
+// core/java/android/os/PowerManager.java.
+String16 RebootReasonToString16(RebootReason reason) {
+ switch (reason) {
+ case RebootReason::DEFAULT:
+ return String16();
+ case RebootReason::RECOVERY:
+ return String16(kRebootReasonRecovery);
+ default:
+ LOG(ERROR) << "Unknown reboot reason " << static_cast<int>(reason);
+ return String16();
+ }
+}
+
+} // namespace
+
+PowerManagerClient::PowerManagerClient()
+ : weak_ptr_factory_(this) {}
+
+PowerManagerClient::~PowerManagerClient() {
+ if (power_manager_.get()) {
+ BinderWrapper::Get()->UnregisterForDeathNotifications(
+ IInterface::asBinder(power_manager_));
+ }
+}
+
+bool PowerManagerClient::Init() {
+ sp<IBinder> power_manager_binder =
+ BinderWrapper::Get()->GetService(kPowerManagerServiceName);
+ if (!power_manager_binder.get()) {
+ LOG(ERROR) << "Didn't get " << kPowerManagerServiceName << " service";
+ return false;
+ }
+
+ BinderWrapper::Get()->RegisterForDeathNotifications(
+ power_manager_binder,
+ base::Bind(&PowerManagerClient::OnPowerManagerDied,
+ weak_ptr_factory_.GetWeakPtr()));
+ power_manager_ = interface_cast<IPowerManager>(power_manager_binder);
+
+ return true;
+}
+
+std::unique_ptr<WakeLock> PowerManagerClient::CreateWakeLock(
+ const std::string& tag,
+ const std::string& package) {
+ std::unique_ptr<WakeLock> lock(new WakeLock(tag, package, this));
+ if (!lock->Init())
+ lock.reset();
+ return lock;
+}
+
+bool PowerManagerClient::Suspend(base::TimeDelta event_uptime,
+ SuspendReason reason,
+ int flags) {
+ DCHECK(power_manager_.get());
+ status_t status = power_manager_->goToSleep(
+ event_uptime.InMilliseconds(), static_cast<int>(reason), flags);
+ if (status != OK) {
+ LOG(ERROR) << "Suspend request failed with status " << status;
+ return false;
+ }
+ return true;
+}
+
+bool PowerManagerClient::ShutDown(ShutdownReason reason) {
+ DCHECK(power_manager_.get());
+ status_t status = power_manager_->shutdown(false /* confirm */,
+ ShutdownReasonToString16(reason),
+ false /* wait */);
+ if (status != OK) {
+ LOG(ERROR) << "Shutdown request failed with status " << status;
+ return false;
+ }
+ return true;
+}
+
+bool PowerManagerClient::Reboot(RebootReason reason) {
+ DCHECK(power_manager_.get());
+ status_t status = power_manager_->reboot(false /* confirm */,
+ RebootReasonToString16(reason),
+ false /* wait */);
+ if (status != OK) {
+ LOG(ERROR) << "Reboot request failed with status " << status;
+ return false;
+ }
+ return true;
+}
+
+void PowerManagerClient::OnPowerManagerDied() {
+ LOG(WARNING) << "Power manager died";
+ power_manager_.clear();
+ // TODO: Try to get a new handle periodically; also consider notifying
+ // previously-created WakeLock objects so they can reacquire locks.
+}
+
+} // namespace android
diff --git a/nativepower/client/power_manager_client_unittest.cc b/nativepower/client/power_manager_client_unittest.cc
new file mode 100644
index 0000000..f27265e
--- /dev/null
+++ b/nativepower/client/power_manager_client_unittest.cc
@@ -0,0 +1,82 @@
+/*
+ * 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/macros.h>
+#include <base/time/time.h>
+#include <binderwrapper/binder_test_base.h>
+#include <binderwrapper/stub_binder_wrapper.h>
+#include <nativepower/constants.h>
+#include <nativepower/power_manager_client.h>
+#include <nativepower/power_manager_stub.h>
+
+namespace android {
+
+class PowerManagerClientTest : public BinderTestBase {
+ public:
+ PowerManagerClientTest()
+ : power_manager_(new PowerManagerStub()),
+ power_manager_binder_(power_manager_) {
+ binder_wrapper()->SetBinderForService(kPowerManagerServiceName,
+ power_manager_binder_);
+ CHECK(client_.Init());
+ }
+ ~PowerManagerClientTest() override = default;
+
+ protected:
+ PowerManagerStub* power_manager_; // Owned by |power_manager_binder_|.
+ sp<IBinder> power_manager_binder_;
+ PowerManagerClient client_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PowerManagerClientTest);
+};
+
+TEST_F(PowerManagerClientTest, Suspend) {
+ EXPECT_EQ(0, power_manager_->num_suspend_requests());
+
+ const auto kEventTime = base::TimeDelta::FromMilliseconds(123);
+ const int kFlags = 0x456;
+ EXPECT_TRUE(client_.Suspend(kEventTime, SuspendReason::POWER_BUTTON, kFlags));
+ EXPECT_EQ(1, power_manager_->num_suspend_requests());
+ EXPECT_EQ(PowerManagerStub::ConstructSuspendRequestString(
+ kEventTime.InMilliseconds(),
+ static_cast<int>(SuspendReason::POWER_BUTTON), kFlags),
+ power_manager_->GetSuspendRequestString(0));
+}
+
+TEST_F(PowerManagerClientTest, ShutDown) {
+ EXPECT_TRUE(client_.ShutDown(ShutdownReason::DEFAULT));
+ ASSERT_EQ(1u, power_manager_->shutdown_reasons().size());
+ EXPECT_EQ("", power_manager_->shutdown_reasons()[0]);
+
+ EXPECT_TRUE(client_.ShutDown(ShutdownReason::USER_REQUESTED));
+ ASSERT_EQ(2u, power_manager_->shutdown_reasons().size());
+ EXPECT_EQ(kShutdownReasonUserRequested,
+ power_manager_->shutdown_reasons()[1]);
+}
+
+TEST_F(PowerManagerClientTest, Reboot) {
+ EXPECT_TRUE(client_.Reboot(RebootReason::DEFAULT));
+ ASSERT_EQ(1u, power_manager_->reboot_reasons().size());
+ EXPECT_EQ("", power_manager_->reboot_reasons()[0]);
+
+ EXPECT_TRUE(client_.Reboot(RebootReason::RECOVERY));
+ ASSERT_EQ(2u, power_manager_->reboot_reasons().size());
+ EXPECT_EQ(kRebootReasonRecovery, power_manager_->reboot_reasons()[1]);
+}
+
+} // namespace android
diff --git a/nativepower/client/wake_lock.cc b/nativepower/client/wake_lock.cc
new file mode 100644
index 0000000..bf65b00
--- /dev/null
+++ b/nativepower/client/wake_lock.cc
@@ -0,0 +1,71 @@
+/*
+ * 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/logging.h>
+#include <binderwrapper/binder_wrapper.h>
+#include <nativepower/power_manager_client.h>
+#include <powermanager/IPowerManager.h>
+#include <powermanager/PowerManager.h>
+
+namespace android {
+
+WakeLock::WakeLock(const std::string& tag,
+ const std::string& package,
+ PowerManagerClient* client)
+ : acquired_lock_(false),
+ tag_(tag),
+ package_(package),
+ client_(client) {
+ DCHECK(client_);
+}
+
+WakeLock::~WakeLock() {
+ sp<IPowerManager> power_manager = client_->power_manager();
+ if (acquired_lock_ && power_manager.get()) {
+ 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;
+ }
+ }
+}
+
+bool WakeLock::Init() {
+ sp<IPowerManager> power_manager = client_->power_manager();
+ if (!power_manager.get()) {
+ LOG(ERROR) << "Can't acquire wake lock for \"" << tag_ << "\"; no "
+ << "connection to power manager";
+ return false;
+ }
+
+ 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_ << "\" failed "
+ << "with status " << status;
+ return false;
+ }
+
+ acquired_lock_ = true;
+ return true;
+}
+
+} // namespace android
diff --git a/nativepower/client/wake_lock_unittest.cc b/nativepower/client/wake_lock_unittest.cc
new file mode 100644
index 0000000..dbd1505
--- /dev/null
+++ b/nativepower/client/wake_lock_unittest.cc
@@ -0,0 +1,76 @@
+/*
+ * 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/logging.h>
+#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_client.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_);
+ CHECK(client_.Init());
+ }
+ ~WakeLockTest() override = default;
+
+ protected:
+ PowerManagerStub* power_manager_; // Owned by |power_manager_binder_|.
+ sp<IBinder> power_manager_binder_;
+ PowerManagerClient client_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WakeLockTest);
+};
+
+TEST_F(WakeLockTest, CreateAndDestroy) {
+ const uid_t kUid = 123;
+ binder_wrapper()->set_calling_uid(kUid);
+ std::unique_ptr<WakeLock> lock(client_.CreateWakeLock("foo", "bar"));
+ ASSERT_EQ(1, power_manager_->GetNumWakeLocks());
+ ASSERT_EQ(1u, binder_wrapper()->local_binders().size());
+ EXPECT_EQ(
+ PowerManagerStub::ConstructWakeLockString("foo", "bar", kUid),
+ power_manager_->GetWakeLockString(binder_wrapper()->local_binders()[0]));
+
+ lock.reset();
+ EXPECT_EQ(0, power_manager_->GetNumWakeLocks());
+}
+
+TEST_F(WakeLockTest, PowerManagerDeath) {
+ std::unique_ptr<WakeLock> lock(client_.CreateWakeLock("foo", "bar"));
+ binder_wrapper()->NotifyAboutBinderDeath(power_manager_binder_);
+
+ // Since PowerManagerClient was informed that the power manager died, WakeLock
+ // shouldn't try to release its lock on destruction.
+ lock.reset();
+ EXPECT_EQ(1, power_manager_->GetNumWakeLocks());
+}
+
+} // namespace android
diff --git a/nativepower/daemon/Android.mk b/nativepower/daemon/Android.mk
new file mode 100644
index 0000000..4a97794
--- /dev/null
+++ b/nativepower/daemon/Android.mk
@@ -0,0 +1,125 @@
+#
+# 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 \
+ external/gtest/include \
+
+nativepowerman_CommonSharedLibraries := \
+ libbinder \
+ libbinderwrapper \
+ libchrome \
+ libcutils \
+ 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 := nativepowerman.rc
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_CFLAGS := $(nativepowerman_CommonCFlags)
+LOCAL_STATIC_LIBRARIES := libnativepowerman
+LOCAL_SHARED_LIBRARIES := \
+ $(nativepowerman_CommonSharedLibraries) \
+ libbrillo \
+ libbrillo-binder \
+
+LOCAL_SRC_FILES := main.cc
+
+include $(BUILD_EXECUTABLE)
+
+# nativepowerman.rc script
+# ========================================================
+
+ifdef INITRC_TEMPLATE
+include $(CLEAR_VARS)
+LOCAL_MODULE := 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,,wakelock)
+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)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../include
+LOCAL_SHARED_LIBRARIES := \
+ $(nativepowerman_CommonSharedLibraries) \
+ libbrillo \
+
+LOCAL_SRC_FILES := \
+ BnPowerManager.cc \
+ power_manager.cc \
+ system_property_setter.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_test_support \
+ libnativepower_test_support \
+
+LOCAL_SRC_FILES := \
+ power_manager_unittest.cc \
+ system_property_setter_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 \
+ wake_lock_manager.cc \
+ wake_lock_manager_stub.cc \
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/nativepower/daemon/BnPowerManager.cc b/nativepower/daemon/BnPowerManager.cc
new file mode 100644
index 0000000..f3bf8bc
--- /dev/null
+++ b/nativepower/daemon/BnPowerManager.cc
@@ -0,0 +1,98 @@
+/*
+ * 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);
+ }
+ case IPowerManager::GO_TO_SLEEP: {
+ CHECK_INTERFACE(IPowerManager, data, reply);
+ int64_t event_time_ms = data.readInt64();
+ int32_t reason = data.readInt32();
+ int32_t flags = data.readInt32();
+ return goToSleep(event_time_ms, reason, flags);
+ }
+ case IPowerManager::REBOOT: {
+ CHECK_INTERFACE(IPowerManager, data, reply);
+ bool confirm = data.readInt32();
+ String16 reason = data.readString16();
+ bool wait = data.readInt32();
+ return reboot(confirm, reason, wait);
+ }
+ case IPowerManager::SHUTDOWN: {
+ CHECK_INTERFACE(IPowerManager, data, reply);
+ bool confirm = data.readInt32();
+ String16 reason = data.readString16();
+ bool wait = data.readInt32();
+ return shutdown(confirm, reason, wait);
+ }
+ case IPowerManager::CRASH: {
+ CHECK_INTERFACE(IPowerManager, data, reply);
+ String16 message = data.readString16();
+ return crash(message);
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+} // namespace android
diff --git a/nativepower/daemon/main.cc b/nativepower/daemon/main.cc
new file mode 100644
index 0000000..479d86f
--- /dev/null
+++ b/nativepower/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 <brillo/binder_watcher.h>
+#include <brillo/daemons/daemon.h>
+#include <brillo/flag_helper.h>
+
+#include "power_manager.h"
+
+namespace {
+
+class PowerManagerDaemon : public brillo::Daemon {
+ public:
+ PowerManagerDaemon() = default;
+ ~PowerManagerDaemon() override = default;
+
+ private:
+ // brillo::Daemon:
+ int OnInit() override {
+ int result = brillo::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;
+ }
+
+ brillo::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.
+ brillo::FlagHelper::Init(argc, argv, "Power management daemon");
+ logging::InitLogging(logging::LoggingSettings());
+ return PowerManagerDaemon().Run();
+}
diff --git a/nativepower/daemon/power_manager.cc b/nativepower/daemon/power_manager.cc
new file mode 100644
index 0000000..2f961b7
--- /dev/null
+++ b/nativepower/daemon/power_manager.cc
@@ -0,0 +1,173 @@
+/*
+ * 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/files/file_util.h>
+#include <base/logging.h>
+#include <base/sys_info.h>
+#include <binderwrapper/binder_wrapper.h>
+#include <cutils/android_reboot.h>
+#include <nativepower/constants.h>
+#include <powermanager/IPowerManager.h>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace {
+
+// Path to real sysfs file that can be written to change the power state.
+const char kDefaultPowerStatePath[] = "/sys/power/state";
+
+} // namespace
+
+const char PowerManager::kRebootPrefix[] = "reboot,";
+const char PowerManager::kShutdownPrefix[] = "shutdown,";
+const char PowerManager::kPowerStateSuspend[] = "mem";
+
+PowerManager::PowerManager()
+ : power_state_path_(kDefaultPowerStatePath) {}
+
+PowerManager::~PowerManager() = default;
+
+bool PowerManager::Init() {
+ if (!property_setter_)
+ property_setter_.reset(new SystemPropertySetter());
+ 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,
+ BinderWrapper::Get()->GetCallingUid())
+ ? 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, static_cast<uid_t>(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;
+}
+
+status_t PowerManager::goToSleep(int64_t event_time_ms, int reason, int flags) {
+ if (event_time_ms < last_resume_uptime_.InMilliseconds()) {
+ LOG(WARNING) << "Ignoring request to suspend in response to event at "
+ << event_time_ms << " preceding last resume time "
+ << last_resume_uptime_.InMilliseconds();
+ return BAD_VALUE;
+ }
+
+ LOG(INFO) << "Suspending immediately for event at " << event_time_ms
+ << " (reason=" << reason << " flags=" << flags << ")";
+ if (base::WriteFile(power_state_path_, kPowerStateSuspend,
+ strlen(kPowerStateSuspend)) !=
+ static_cast<int>(strlen(kPowerStateSuspend))) {
+ PLOG(ERROR) << "Failed to write \"" << kPowerStateSuspend << "\" to "
+ << power_state_path_.value();
+ return UNKNOWN_ERROR;
+ }
+
+ last_resume_uptime_ = base::SysInfo::Uptime();
+ LOG(INFO) << "Resumed from suspend at "
+ << last_resume_uptime_.InMilliseconds();
+ return OK;
+}
+
+status_t PowerManager::reboot(bool confirm, const String16& reason, bool wait) {
+ const std::string reason_str(String8(reason).string());
+ if (!(reason_str.empty() || reason_str == kRebootReasonRecovery)) {
+ LOG(WARNING) << "Ignoring reboot request with invalid reason \""
+ << reason_str << "\"";
+ return BAD_VALUE;
+ }
+
+ LOG(INFO) << "Rebooting with reason \"" << reason_str << "\"";
+ if (!property_setter_->SetProperty(ANDROID_RB_PROPERTY,
+ kRebootPrefix + reason_str)) {
+ return UNKNOWN_ERROR;
+ }
+ return OK;
+}
+
+status_t PowerManager::shutdown(bool confirm,
+ const String16& reason,
+ bool wait) {
+ const std::string reason_str(String8(reason).string());
+ if (!(reason_str.empty() || reason_str == kShutdownReasonUserRequested)) {
+ LOG(WARNING) << "Ignoring shutdown request with invalid reason \""
+ << reason_str << "\"";
+ return BAD_VALUE;
+ }
+
+ LOG(INFO) << "Shutting down with reason \"" << reason_str << "\"";
+ if (!property_setter_->SetProperty(ANDROID_RB_PROPERTY,
+ kShutdownPrefix + reason_str)) {
+ return UNKNOWN_ERROR;
+ }
+ return OK;
+}
+
+status_t PowerManager::crash(const String16& message) {
+ NOTIMPLEMENTED() << "crash: message=" << message;
+ 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/nativepower/daemon/power_manager.h b/nativepower/daemon/power_manager.h
new file mode 100644
index 0000000..0428b81
--- /dev/null
+++ b/nativepower/daemon/power_manager.h
@@ -0,0 +1,112 @@
+/*
+ * 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/files/file_path.h>
+#include <base/macros.h>
+#include <base/time/time.h>
+#include <nativepower/BnPowerManager.h>
+
+#include "system_property_setter.h"
+#include "wake_lock_manager.h"
+
+namespace android {
+
+class PowerManager : public BnPowerManager {
+ public:
+ // The part of the reboot or shutdown system properties' values that appears
+ // before the reason. These strings are hardcoded in
+ // system/core/init/builtins.cpp.
+ static const char kRebootPrefix[];
+ static const char kShutdownPrefix[];
+
+ // Value written to |power_state_path_| to suspend the system to memory.
+ static const char kPowerStateSuspend[];
+
+ PowerManager();
+ ~PowerManager() override;
+
+ // Must be called before Init().
+ void set_property_setter_for_testing(
+ std::unique_ptr<SystemPropertySetterInterface> setter) {
+ property_setter_ = std::move(setter);
+ }
+
+ // Must be called before Init().
+ void set_wake_lock_manager_for_testing(
+ std::unique_ptr<WakeLockManagerInterface> manager) {
+ wake_lock_manager_ = std::move(manager);
+ }
+
+ void set_power_state_path_for_testing(const base::FilePath& path) {
+ power_state_path_ = path;
+ }
+
+ // 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;
+ status_t goToSleep(int64_t event_time_ms, int reason, int flags) override;
+ status_t reboot(bool confirm, const String16& reason, bool wait) override;
+ status_t shutdown(bool confirm, const String16& reason, bool wait) override;
+ status_t crash(const String16& message) 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<SystemPropertySetterInterface> property_setter_;
+ std::unique_ptr<WakeLockManagerInterface> wake_lock_manager_;
+
+ // Path to sysfs file that can be written to change the power state.
+ base::FilePath power_state_path_;
+
+ // System uptime (as duration since boot) when userspace was last resumed from
+ // suspend. Initially unset.
+ base::TimeDelta last_resume_uptime_;
+
+ DISALLOW_COPY_AND_ASSIGN(PowerManager);
+};
+
+} // namespace android
+
+#endif // SYSTEM_NATIVEPOWER_DAEMON_POWER_MANAGER_H_
diff --git a/nativepower/daemon/power_manager_stub.cc b/nativepower/daemon/power_manager_stub.cc
new file mode 100644
index 0000000..bb2588a
--- /dev/null
+++ b/nativepower/daemon/power_manager_stub.cc
@@ -0,0 +1,140 @@
+/*
+ * 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/format_macros.h>
+#include <base/logging.h>
+#include <base/strings/stringprintf.h>
+#include <binderwrapper/binder_wrapper.h>
+#include <nativepower/power_manager_stub.h>
+#include <utils/String8.h>
+
+#include "wake_lock_manager_stub.h"
+
+namespace android {
+
+PowerManagerStub::SuspendRequest::SuspendRequest(int64_t event_time_ms,
+ int reason,
+ int flags)
+ : event_time_ms(event_time_ms),
+ reason(reason),
+ flags(flags) {}
+
+// static
+std::string PowerManagerStub::ConstructWakeLockString(
+ const std::string& tag,
+ const std::string& package,
+ uid_t uid) {
+ return WakeLockManagerStub::ConstructRequestString(tag, package, uid);
+}
+
+// static
+std::string PowerManagerStub::ConstructSuspendRequestString(
+ int64_t event_time_ms,
+ int reason,
+ int flags) {
+ return base::StringPrintf("%" PRId64 ",%d,%d", event_time_ms, reason, flags);
+}
+
+PowerManagerStub::PowerManagerStub()
+ : wake_lock_manager_(new WakeLockManagerStub()) {}
+
+PowerManagerStub::~PowerManagerStub() = default;
+
+int PowerManagerStub::GetNumWakeLocks() const {
+ return wake_lock_manager_->num_requests();
+}
+
+std::string PowerManagerStub::GetWakeLockString(
+ const sp<IBinder>& binder) const {
+ return wake_lock_manager_->GetRequestString(binder);
+}
+
+std::string PowerManagerStub::GetSuspendRequestString(size_t index) const {
+ if (index >= suspend_requests_.size())
+ return std::string();
+
+ const SuspendRequest& request = suspend_requests_[index];
+ return ConstructSuspendRequestString(request.event_time_ms, request.reason,
+ request.flags);
+}
+
+status_t PowerManagerStub::acquireWakeLock(int flags,
+ const sp<IBinder>& lock,
+ const String16& tag,
+ const String16& packageName,
+ bool isOneWay) {
+ CHECK(wake_lock_manager_->AddRequest(lock, String8(tag).string(),
+ String8(packageName).string(),
+ BinderWrapper::Get()->GetCallingUid()));
+ return OK;
+}
+
+status_t PowerManagerStub::acquireWakeLockWithUid(int flags,
+ const sp<IBinder>& lock,
+ const String16& tag,
+ const String16& packageName,
+ int uid,
+ bool isOneWay) {
+ CHECK(wake_lock_manager_->AddRequest(lock, String8(tag).string(),
+ String8(packageName).string(),
+ static_cast<uid_t>(uid)));
+ return OK;
+}
+
+status_t PowerManagerStub::releaseWakeLock(const sp<IBinder>& lock,
+ int flags,
+ bool isOneWay) {
+ CHECK(wake_lock_manager_->RemoveRequest(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;
+}
+
+status_t PowerManagerStub::goToSleep(int64_t event_time_ms,
+ int reason,
+ int flags) {
+ suspend_requests_.emplace_back(event_time_ms, reason, flags);
+ return OK;
+}
+
+status_t PowerManagerStub::reboot(bool confirm,
+ const String16& reason,
+ bool wait) {
+ reboot_reasons_.push_back(String8(reason).string());
+ return OK;
+}
+
+status_t PowerManagerStub::shutdown(bool confirm,
+ const String16& reason,
+ bool wait) {
+ shutdown_reasons_.push_back(String8(reason).string());
+ return OK;
+}
+
+status_t PowerManagerStub::crash(const String16& message) {
+ return OK;
+}
+
+} // namespace android
diff --git a/nativepower/daemon/power_manager_unittest.cc b/nativepower/daemon/power_manager_unittest.cc
new file mode 100644
index 0000000..c221ace
--- /dev/null
+++ b/nativepower/daemon/power_manager_unittest.cc
@@ -0,0 +1,176 @@
+/*
+ * 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_util.h>
+#include <base/files/scoped_temp_dir.h>
+#include <base/macros.h>
+#include <base/sys_info.h>
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+#include <binderwrapper/binder_test_base.h>
+#include <binderwrapper/stub_binder_wrapper.h>
+#include <cutils/android_reboot.h>
+#include <nativepower/constants.h>
+#include <powermanager/PowerManager.h>
+
+#include "power_manager.h"
+#include "system_property_setter_stub.h"
+#include "wake_lock_manager_stub.h"
+
+namespace android {
+
+class PowerManagerTest : public BinderTestBase {
+ public:
+ PowerManagerTest()
+ : power_manager_(new PowerManager()),
+ interface_(interface_cast<IPowerManager>(power_manager_)),
+ property_setter_(new SystemPropertySetterStub()),
+ wake_lock_manager_(new WakeLockManagerStub()) {
+ CHECK(temp_dir_.CreateUniqueTempDir());
+
+ power_state_path_ = temp_dir_.path().Append("power_state");
+ power_manager_->set_power_state_path_for_testing(power_state_path_);
+ ClearPowerState();
+
+ power_manager_->set_property_setter_for_testing(
+ std::unique_ptr<SystemPropertySetterInterface>(property_setter_));
+ power_manager_->set_wake_lock_manager_for_testing(
+ std::unique_ptr<WakeLockManagerInterface>(wake_lock_manager_));
+
+ CHECK(power_manager_->Init());
+ }
+ ~PowerManagerTest() override = default;
+
+ protected:
+ // Returns the value in |power_state_path_|.
+ std::string ReadPowerState() {
+ std::string state;
+ PCHECK(base::ReadFileToString(power_state_path_, &state))
+ << "Failed to read " << power_state_path_.value();
+ return state;
+ }
+
+ // Clears |power_state_path_|.
+ void ClearPowerState() {
+ PCHECK(base::WriteFile(power_state_path_, "", 0) == 0)
+ << "Failed to write " << power_state_path_.value();
+ }
+
+ base::ScopedTempDir temp_dir_;
+ sp<PowerManager> power_manager_;
+ sp<IPowerManager> interface_;
+ SystemPropertySetterStub* property_setter_; // Owned by |power_manager_|.
+ WakeLockManagerStub* wake_lock_manager_; // Owned by |power_manager_|.
+
+ // File under |temp_dir_| used in place of /sys/power/state.
+ base::FilePath power_state_path_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PowerManagerTest);
+};
+
+TEST_F(PowerManagerTest, RegisterService) {
+ EXPECT_EQ(power_manager_,
+ binder_wrapper()->GetRegisteredService(kPowerManagerServiceName));
+}
+
+TEST_F(PowerManagerTest, AcquireAndReleaseWakeLock) {
+ const char kTag[] = "foo";
+ const char kPackage[] = "bar";
+ sp<BBinder> binder = binder_wrapper()->CreateLocalBinder();
+
+ // Check that PowerManager looks up the calling UID when necessary.
+ const uid_t kCallingUid = 100;
+ binder_wrapper()->set_calling_uid(kCallingUid);
+ EXPECT_EQ(OK, interface_->acquireWakeLock(0, binder, String16(kTag),
+ String16(kPackage)));
+ EXPECT_EQ(1, wake_lock_manager_->num_requests());
+ EXPECT_EQ(
+ WakeLockManagerStub::ConstructRequestString(kTag, kPackage, kCallingUid),
+ wake_lock_manager_->GetRequestString(
+ binder_wrapper()->local_binders()[0]));
+
+ EXPECT_EQ(OK, interface_->releaseWakeLock(binder, 0));
+ EXPECT_EQ(0, wake_lock_manager_->num_requests());
+
+ // If a UID is passed, it should be used instead.
+ const uid_t kPassedUid = 200;
+ EXPECT_EQ(OK, interface_->acquireWakeLockWithUid(
+ 0, binder, String16(kTag), String16(kPackage), kPassedUid));
+ EXPECT_EQ(1, wake_lock_manager_->num_requests());
+ EXPECT_EQ(
+ WakeLockManagerStub::ConstructRequestString(kTag, kPackage, kPassedUid),
+ wake_lock_manager_->GetRequestString(
+ binder_wrapper()->local_binders()[0]));
+}
+
+TEST_F(PowerManagerTest, GoToSleep) {
+ EXPECT_EQ("", ReadPowerState());
+
+ const int64_t kStartTime = base::SysInfo::Uptime().InMilliseconds();
+ EXPECT_EQ(OK,
+ interface_->goToSleep(kStartTime, 0 /* reason */, 0 /* flags */));
+ EXPECT_EQ(PowerManager::kPowerStateSuspend, ReadPowerState());
+
+ // A request with a timestamp preceding the last resume should be ignored.
+ ClearPowerState();
+ EXPECT_EQ(BAD_VALUE, interface_->goToSleep(kStartTime - 1, 0, 0));
+ EXPECT_EQ("", ReadPowerState());
+
+ // A second attempt with a timestamp occurring after the last
+ // resume should be honored.
+ ClearPowerState();
+ EXPECT_EQ(
+ OK,
+ interface_->goToSleep(base::SysInfo::Uptime().InMilliseconds(), 0, 0));
+ EXPECT_EQ(PowerManager::kPowerStateSuspend, ReadPowerState());
+}
+
+TEST_F(PowerManagerTest, Reboot) {
+ EXPECT_EQ(OK, interface_->reboot(false, String16(), false));
+ EXPECT_EQ(PowerManager::kRebootPrefix,
+ property_setter_->GetProperty(ANDROID_RB_PROPERTY));
+
+ EXPECT_EQ(OK, interface_->reboot(false, String16(kRebootReasonRecovery),
+ false));
+ EXPECT_EQ(std::string(PowerManager::kRebootPrefix) + kRebootReasonRecovery,
+ property_setter_->GetProperty(ANDROID_RB_PROPERTY));
+
+ // Invalid values should be rejected.
+ ASSERT_TRUE(property_setter_->SetProperty(ANDROID_RB_PROPERTY, ""));
+ EXPECT_EQ(BAD_VALUE, interface_->reboot(false, String16("foo"), false));
+ EXPECT_EQ("", property_setter_->GetProperty(ANDROID_RB_PROPERTY));
+}
+
+TEST_F(PowerManagerTest, Shutdown) {
+ EXPECT_EQ(OK, interface_->shutdown(false, String16(), false));
+ EXPECT_EQ(PowerManager::kShutdownPrefix,
+ property_setter_->GetProperty(ANDROID_RB_PROPERTY));
+
+ EXPECT_EQ(OK, interface_->shutdown(false,
+ String16(kShutdownReasonUserRequested),
+ false));
+ EXPECT_EQ(std::string(PowerManager::kShutdownPrefix) +
+ kShutdownReasonUserRequested,
+ property_setter_->GetProperty(ANDROID_RB_PROPERTY));
+
+ // Invalid values should be rejected.
+ ASSERT_TRUE(property_setter_->SetProperty(ANDROID_RB_PROPERTY, ""));
+ EXPECT_EQ(BAD_VALUE, interface_->shutdown(false, String16("foo"), false));
+ EXPECT_EQ("", property_setter_->GetProperty(ANDROID_RB_PROPERTY));
+}
+
+} // namespace android
diff --git a/nativepower/daemon/system_property_setter.cc b/nativepower/daemon/system_property_setter.cc
new file mode 100644
index 0000000..9368f54
--- /dev/null
+++ b/nativepower/daemon/system_property_setter.cc
@@ -0,0 +1,32 @@
+/*
+ * 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 "system_property_setter.h"
+
+#include <cutils/properties.h>
+
+namespace android {
+
+SystemPropertySetter::SystemPropertySetter() = default;
+
+SystemPropertySetter::~SystemPropertySetter() = default;
+
+bool SystemPropertySetter::SetProperty(const std::string& key,
+ const std::string& value) {
+ return property_set(key.c_str(), value.c_str()) == 0;
+}
+
+} // namespace android
diff --git a/nativepower/daemon/system_property_setter.h b/nativepower/daemon/system_property_setter.h
new file mode 100644
index 0000000..8ccd2c3
--- /dev/null
+++ b/nativepower/daemon/system_property_setter.h
@@ -0,0 +1,52 @@
+/*
+ * 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_SYSTEM_PROPERTY_SETTER_H_
+#define SYSTEM_NATIVEPOWER_DAEMON_SYSTEM_PROPERTY_SETTER_H_
+
+#include <string>
+
+#include <base/macros.h>
+
+namespace android {
+
+// An interface for setting Android system properties.
+class SystemPropertySetterInterface {
+ public:
+ SystemPropertySetterInterface() {}
+ virtual ~SystemPropertySetterInterface() {}
+
+ // Sets the property named |key| to |value|, returning true on success.
+ virtual bool SetProperty(const std::string& key,
+ const std::string& value) = 0;
+};
+
+// The real implementation of SystemPropertySetterInterface.
+class SystemPropertySetter : public SystemPropertySetterInterface {
+ public:
+ SystemPropertySetter();
+ ~SystemPropertySetter() override;
+
+ // SystemPropertySetterInterface:
+ bool SetProperty(const std::string& key, const std::string& value) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SystemPropertySetter);
+};
+
+} // namespace android
+
+#endif // SYSTEM_NATIVEPOWER_DAEMON_SYSTEM_PROPERTY_SETTER_H_
diff --git a/nativepower/daemon/system_property_setter_stub.cc b/nativepower/daemon/system_property_setter_stub.cc
new file mode 100644
index 0000000..d07212f
--- /dev/null
+++ b/nativepower/daemon/system_property_setter_stub.cc
@@ -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.
+ */
+
+#include "system_property_setter_stub.h"
+
+namespace android {
+
+SystemPropertySetterStub::SystemPropertySetterStub() = default;
+
+SystemPropertySetterStub::~SystemPropertySetterStub() = default;
+
+std::string SystemPropertySetterStub::GetProperty(
+ const std::string& key) const {
+ const auto it = properties_.find(key);
+ return it != properties_.end() ? it->second : std::string();
+}
+
+bool SystemPropertySetterStub::SetProperty(const std::string& key,
+ const std::string& value) {
+ properties_[key] = value;
+ return true;
+}
+
+} // namespace android
diff --git a/nativepower/daemon/system_property_setter_stub.h b/nativepower/daemon/system_property_setter_stub.h
new file mode 100644
index 0000000..b84a72a
--- /dev/null
+++ b/nativepower/daemon/system_property_setter_stub.h
@@ -0,0 +1,50 @@
+/*
+ * 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_SYSTEM_PROPERTY_SETTER_STUB_H_
+#define SYSTEM_NATIVEPOWER_DAEMON_SYSTEM_PROPERTY_SETTER_STUB_H_
+
+#include <map>
+#include <string>
+
+#include <base/macros.h>
+
+#include "system_property_setter.h"
+
+namespace android {
+
+// A stub implementation of SystemPropertySetterInterface for use by tests.
+class SystemPropertySetterStub : public SystemPropertySetterInterface {
+ public:
+ SystemPropertySetterStub();
+ ~SystemPropertySetterStub() override;
+
+ // Returns the value for |key|. An empty string is returned for an unset
+ // property.
+ std::string GetProperty(const std::string& key) const;
+
+ // SystemPropertySetterInterface:
+ bool SetProperty(const std::string& key, const std::string& value) override;
+
+ private:
+ std::map<std::string, std::string> properties_;
+
+ DISALLOW_COPY_AND_ASSIGN(SystemPropertySetterStub);
+};
+
+} // namespace android
+
+#endif // SYSTEM_NATIVEPOWER_DAEMON_SYSTEM_PROPERTY_SETTER_STUB_H_
diff --git a/nativepower/daemon/wake_lock_manager.cc b/nativepower/daemon/wake_lock_manager.cc
new file mode 100644
index 0000000..37de1e3
--- /dev/null
+++ b/nativepower/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,
+ uid_t uid)
+ : tag(tag),
+ package(package),
+ uid(uid) {}
+
+WakeLockManager::Request::Request(const Request& request) = default;
+
+WakeLockManager::Request::Request() : uid(-1) {}
+
+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,
+ uid_t 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/nativepower/daemon/wake_lock_manager.h b/nativepower/daemon/wake_lock_manager.h
new file mode 100644
index 0000000..cc4dcc9
--- /dev/null
+++ b/nativepower/daemon/wake_lock_manager.h
@@ -0,0 +1,95 @@
+/*
+ * 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 <sys/types.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,
+ uid_t uid) = 0;
+ virtual bool RemoveRequest(sp<IBinder> client_binder) = 0;
+
+ protected:
+ // Information about a request from a client.
+ struct Request {
+ Request(const std::string& tag, const std::string& package, uid_t uid);
+ Request(const Request& request);
+ Request();
+
+ std::string tag;
+ std::string package;
+ uid_t uid;
+ };
+};
+
+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,
+ uid_t uid) override;
+ bool RemoveRequest(sp<IBinder> client_binder) override;
+
+ private:
+ 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/nativepower/daemon/wake_lock_manager_stub.cc b/nativepower/daemon/wake_lock_manager_stub.cc
new file mode 100644
index 0000000..3b56c4e
--- /dev/null
+++ b/nativepower/daemon/wake_lock_manager_stub.cc
@@ -0,0 +1,62 @@
+/*
+ * 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 <base/strings/stringprintf.h>
+#include <binder/IBinder.h>
+
+namespace android {
+
+// static
+std::string WakeLockManagerStub::ConstructRequestString(
+ const std::string& tag,
+ const std::string& package,
+ uid_t uid) {
+ return base::StringPrintf("%s,%s,%d", tag.c_str(), package.c_str(), uid);
+}
+
+WakeLockManagerStub::WakeLockManagerStub() = default;
+
+WakeLockManagerStub::~WakeLockManagerStub() = default;
+
+std::string WakeLockManagerStub::GetRequestString(
+ const sp<IBinder>& binder) const {
+ const auto it = requests_.find(binder);
+ if (it == requests_.end())
+ return std::string();
+
+ const Request& req = it->second;
+ return ConstructRequestString(req.tag, req.package, req.uid);
+}
+
+bool WakeLockManagerStub::AddRequest(sp<IBinder> client_binder,
+ const std::string& tag,
+ const std::string& package,
+ uid_t uid) {
+ requests_[client_binder] = Request(tag, package, uid);
+ return true;
+}
+
+bool WakeLockManagerStub::RemoveRequest(sp<IBinder> client_binder) {
+ if (!requests_.count(client_binder))
+ return false;
+
+ requests_.erase(client_binder);
+ return true;
+}
+
+} // namespace android
diff --git a/nativepower/daemon/wake_lock_manager_stub.h b/nativepower/daemon/wake_lock_manager_stub.h
new file mode 100644
index 0000000..d720143
--- /dev/null
+++ b/nativepower/daemon/wake_lock_manager_stub.h
@@ -0,0 +1,67 @@
+/*
+ * 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 <sys/types.h>
+
+#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:
+ WakeLockManagerStub();
+ ~WakeLockManagerStub() override;
+
+ // Constructs a string that can be compared with one returned by
+ // GetRequestString().
+ static std::string ConstructRequestString(const std::string& tag,
+ const std::string& package,
+ uid_t uid);
+
+ int num_requests() const { return requests_.size(); }
+
+ // Returns a string describing the request associated with |binder|, or an
+ // empty string if no request is present.
+ std::string GetRequestString(const sp<IBinder>& binder) const;
+
+ // WakeLockManagerInterface:
+ bool AddRequest(sp<IBinder> client_binder,
+ const std::string& tag,
+ const std::string& package,
+ uid_t uid) override;
+ bool RemoveRequest(sp<IBinder> client_binder) override;
+
+ private:
+ // Currently-active requests, keyed by client binders.
+ std::map<sp<IBinder>, Request> requests_;
+
+ DISALLOW_COPY_AND_ASSIGN(WakeLockManagerStub);
+};
+
+} // namespace android
+
+#endif // SYSTEM_NATIVEPOWER_DAEMON_WAKE_LOCK_MANAGER_STUB_H_
diff --git a/nativepower/daemon/wake_lock_manager_unittest.cc b/nativepower/daemon/wake_lock_manager_unittest.cc
new file mode 100644
index 0000000..887b564
--- /dev/null
+++ b/nativepower/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/nativepower/example/Android.mk b/nativepower/example/Android.mk
new file mode 100644
index 0000000..88ad156
--- /dev/null
+++ b/nativepower/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 \
+ libbrillo \
+ libchrome \
+ libnativepower \
+ libpowermanager \
+ libutils \
+
+LOCAL_SRC_FILES := \
+ power_example.cc \
+
+include $(BUILD_EXECUTABLE)
diff --git a/nativepower/example/power_example.cc b/nativepower/example/power_example.cc
new file mode 100644
index 0000000..494c052
--- /dev/null
+++ b/nativepower/example/power_example.cc
@@ -0,0 +1,75 @@
+/*
+ * 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 <base/sys_info.h>
+#include <base/time/time.h>
+#include <binderwrapper/binder_wrapper.h>
+#include <brillo/flag_helper.h>
+#include <nativepower/power_manager_client.h>
+#include <nativepower/wake_lock.h>
+
+namespace {
+
+// Seconds to sleep after acquiring a wake lock.
+const int kWakeLockSleepSec = 5;
+
+} // namespace
+
+int main(int argc, char *argv[]) {
+ DEFINE_string(action, "",
+ "Action to perform (\"reboot\", \"shut_down\", \"suspend\", "
+ "\"wake_lock\")");
+
+ brillo::FlagHelper::Init(argc, argv, "Example power-management client.");
+ logging::InitLogging(logging::LoggingSettings());
+ base::AtExitManager at_exit;
+ base::MessageLoopForIO loop;
+ android::BinderWrapper::Create();
+
+ android::PowerManagerClient client;
+ CHECK(client.Init());
+
+ if (FLAGS_action == "reboot") {
+ LOG(INFO) << "Requesting reboot";
+ CHECK(client.Reboot(android::RebootReason::DEFAULT));
+ } else if (FLAGS_action == "shut_down") {
+ LOG(INFO) << "Requesting shutdown";
+ CHECK(client.ShutDown(android::ShutdownReason::DEFAULT));
+ } else if (FLAGS_action == "suspend") {
+ LOG(INFO) << "Requesting suspend";
+ CHECK(client.Suspend(base::SysInfo::Uptime(),
+ android::SuspendReason::APPLICATION, 0 /* flags */));
+ } else if (FLAGS_action == "wake_lock") {
+ LOG(INFO) << "Creating wake lock";
+ std::unique_ptr<android::WakeLock> lock(
+ client.CreateWakeLock("power_example", "power"));
+ CHECK(lock) << "Lock not created";
+ LOG(INFO) << "Sleeping for " << kWakeLockSleepSec << " seconds";
+ sleep(kWakeLockSleepSec);
+ } else {
+ LOG(FATAL) << "Unknown action \"" << FLAGS_action << "\"";
+ }
+
+ LOG(INFO) << "Exiting";
+ return 0;
+}
diff --git a/nativepower/include/nativepower/BnPowerManager.h b/nativepower/include/nativepower/BnPowerManager.h
new file mode 100644
index 0000000..db14ef3
--- /dev/null
+++ b/nativepower/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/nativepower/include/nativepower/constants.h b/nativepower/include/nativepower/constants.h
new file mode 100644
index 0000000..9ceeb40
--- /dev/null
+++ b/nativepower/include/nativepower/constants.h
@@ -0,0 +1,32 @@
+/*
+ * 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";
+
+// Reasons that can be supplied for reboot or shutdown requests.
+// These strings are hardcoded in system/core/init/builtins.cpp.
+const char kRebootReasonRecovery[] = "recovery";
+const char kShutdownReasonUserRequested[] = "userrequested";
+
+} // namespace android
+
+#endif // SYSTEM_NATIVEPOWER_INCLUDE_NATIVEPOWER_CONSTANTS_H_
diff --git a/nativepower/include/nativepower/power_manager_client.h b/nativepower/include/nativepower/power_manager_client.h
new file mode 100644
index 0000000..e8528b4
--- /dev/null
+++ b/nativepower/include/nativepower/power_manager_client.h
@@ -0,0 +1,106 @@
+/*
+ * 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 <string>
+
+#include <base/macros.h>
+#include <base/memory/weak_ptr.h>
+#include <base/time/time.h>
+#include <nativepower/wake_lock.h>
+#include <powermanager/IPowerManager.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+// Reasons that can be passed to PowerManagerClient::Suspend().
+enum class SuspendReason {
+ // These values must match the ones in android.os.PowerManager.
+ APPLICATION = 0,
+ DEVICE_ADMIN = 1,
+ TIMEOUT = 2,
+ LID_SWITCH = 3,
+ POWER_BUTTON = 4,
+ HDMI = 5,
+ SLEEP_BUTTON = 6,
+};
+
+enum class SuspendFlags {
+ // Corresponds to GO_TO_SLEEP_FLAG_NO_DOZE in android.os.PowerManager.
+ NO_DOZE = 1 << 0,
+};
+
+// Reasons that can be passed to PowerManagerClient::ShutDown().
+enum class ShutdownReason {
+ DEFAULT,
+ USER_REQUESTED,
+};
+
+// Reasons that can be passed to PowerManagerClient::Reboot().
+enum class RebootReason {
+ DEFAULT,
+ RECOVERY,
+};
+
+// Class used to communicate with the system power manager.
+//
+// android::BinderWrapper must be initialized before constructing this class.
+class PowerManagerClient {
+ public:
+ PowerManagerClient();
+ ~PowerManagerClient();
+
+ // This should not be used directly; it's just exposed for WakeLock.
+ const sp<IPowerManager>& power_manager() { return power_manager_; }
+
+ // Initializes the object, returning true on success. Must be called before
+ // any other methods.
+ bool Init();
+
+ // Creates and returns a wake lock identified by |tag| and |package|. The
+ // returned WakeLock object will block power management until it is destroyed.
+ // An empty pointer is returned on failure (e.g. due to issues communicating
+ // with the power manager).
+ std::unique_ptr<WakeLock> CreateWakeLock(const std::string& tag,
+ const std::string& package);
+
+ // Suspends the system immediately, returning true on success.
+ //
+ // |event_uptime| contains the time since the system was booted (e.g.
+ // base::SysInfo::Uptime()) of the event that triggered the suspend request.
+ // It is used to avoid acting on stale suspend requests that are sent before
+ // the currently-active suspend request completes.
+ // |reason| is currently only used by android.view.WindowManagerPolicy.
+ // |flags| is a bitfield of SuspendFlag values.
+ bool Suspend(base::TimeDelta event_uptime, SuspendReason reason, int flags);
+
+ // Shuts down or reboots the system, returning true on success.
+ bool ShutDown(ShutdownReason reason);
+ bool Reboot(RebootReason reason);
+
+ private:
+ // Called in response to |power_manager_|'s binder dying.
+ void OnPowerManagerDied();
+
+ // Interface for communicating with the power manager.
+ sp<IPowerManager> power_manager_;
+
+ // Keep this member last.
+ base::WeakPtrFactory<PowerManagerClient> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PowerManagerClient);
+};
+
+} // namespace android
diff --git a/nativepower/include/nativepower/power_manager_stub.h b/nativepower/include/nativepower/power_manager_stub.h
new file mode 100644
index 0000000..572a403
--- /dev/null
+++ b/nativepower/include/nativepower/power_manager_stub.h
@@ -0,0 +1,118 @@
+/*
+ * 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 <sys/types.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+#include <nativepower/BnPowerManager.h>
+
+namespace android {
+
+class WakeLockManagerStub;
+
+// Stub implementation of BnPowerManager for use in tests.
+//
+// The BinderWrapper singleton must be initialized before using this class.
+class PowerManagerStub : public BnPowerManager {
+ public:
+ PowerManagerStub();
+ ~PowerManagerStub() override;
+
+ // Constructs a string that can be compared with one returned by
+ // GetWakeLockString().
+ static std::string ConstructWakeLockString(const std::string& tag,
+ const std::string& package,
+ uid_t uid);
+
+ // Constructs a string that can be compared with one returned by
+ // GetSuspendRequestString().
+ static std::string ConstructSuspendRequestString(int64_t event_time_ms,
+ int reason,
+ int flags);
+
+ size_t num_suspend_requests() const { return suspend_requests_.size(); }
+ const std::vector<std::string>& reboot_reasons() const {
+ return reboot_reasons_;
+ }
+ const std::vector<std::string>& shutdown_reasons() const {
+ return shutdown_reasons_;
+ }
+
+ // Returns the number of currently-registered wake locks.
+ int GetNumWakeLocks() const;
+
+ // Returns a string describing the wake lock registered for |binder|, or an
+ // empty string if no wake lock is present.
+ std::string GetWakeLockString(const sp<IBinder>& binder) const;
+
+ // Returns a string describing position |index| in |suspend_requests_|.
+ std::string GetSuspendRequestString(size_t index) 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;
+ status_t goToSleep(int64_t event_time_ms, int reason, int flags) override;
+ status_t reboot(bool confirm, const String16& reason, bool wait) override;
+ status_t shutdown(bool confirm, const String16& reason, bool wait) override;
+ status_t crash(const String16& message) override;
+
+ private:
+ // Details about a request passed to goToSleep().
+ struct SuspendRequest {
+ SuspendRequest(int64_t uptime_ms, int reason, int flags);
+
+ int64_t event_time_ms;
+ int reason;
+ int flags;
+ };
+
+ std::unique_ptr<WakeLockManagerStub> wake_lock_manager_;
+
+ // Information about calls to goToSleep(), in the order they were made.
+ using SuspendRequests = std::vector<SuspendRequest>;
+ SuspendRequests suspend_requests_;
+
+ // Reasons passed to reboot() and shutdown(), in the order in which they were
+ // received.
+ std::vector<std::string> reboot_reasons_;
+ std::vector<std::string> shutdown_reasons_;
+
+ DISALLOW_COPY_AND_ASSIGN(PowerManagerStub);
+};
+
+} // namespace android
diff --git a/nativepower/include/nativepower/wake_lock.h b/nativepower/include/nativepower/wake_lock.h
new file mode 100644
index 0000000..faa9d8a
--- /dev/null
+++ b/nativepower/include/nativepower/wake_lock.h
@@ -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.
+ */
+
+#ifndef SYSTEM_NATIVEPOWER_INCLUDE_NATIVEPOWER_WAKE_LOCK_H_
+#define SYSTEM_NATIVEPOWER_INCLUDE_NATIVEPOWER_WAKE_LOCK_H_
+
+#include <string>
+
+#include <base/macros.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class IBinder;
+class PowerManagerClient;
+
+// RAII-style class that prevents the system from suspending.
+//
+// Instantiate by calling PowerManagerClient::CreateWakeLock().
+class WakeLock {
+ public:
+ ~WakeLock();
+
+ private:
+ friend class PowerManagerClient;
+
+ // Ownership of |client| remains with the caller.
+ WakeLock(const std::string& tag,
+ const std::string& package,
+ PowerManagerClient* client);
+
+ // Initializes the object and acquires the lock, returning true on success.
+ bool Init();
+
+ // Was a lock successfully acquired from the power manager?
+ bool acquired_lock_;
+
+ std::string tag_;
+ std::string package_;
+
+ // Weak pointer to the client that created this wake lock.
+ PowerManagerClient* client_;
+
+ // 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_