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_