aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Erat <derat@google.com>2015-09-30 17:04:48 -0600
committerDaniel Erat <derat@google.com>2015-10-02 16:07:17 -0600
commitc2a4b05a931fbf3ecbf1915049b549b33dae8ba5 (patch)
tree09f634d0354560e0576b9b774fd8910ad14fce7b
parent77ca78c8d297564db431a5b3a9165e170bb7c72a (diff)
downloadnativepower-c2a4b05a931fbf3ecbf1915049b549b33dae8ba5.tar.gz
Support shutting down and rebooting.
Implement the shutdown and reboot Binder methods from the IPowerManager interface. Also introduce a new PowerManagerClient class within libnativepower. Programs that wish to interact with the power manager should instantiate it a PowerManagerClient and then use it to issue commands to the power manager and to create WakeLock objects. Bug: 22122485 Change-Id: Id82d9221d7f90c18ae12221334e35ffd6e488e17
-rw-r--r--client/Android.mk2
-rw-r--r--client/power_manager_client.cc127
-rw-r--r--client/power_manager_client_unittest.cc68
-rw-r--r--client/wake_lock.cc55
-rw-r--r--client/wake_lock_unittest.cc16
-rw-r--r--daemon/Android.mk3
-rw-r--r--daemon/BnPowerManager.cc26
-rw-r--r--daemon/power_manager.cc33
-rw-r--r--daemon/power_manager.h14
-rw-r--r--daemon/power_manager_stub.cc2
-rw-r--r--daemon/power_manager_unittest.cc51
-rw-r--r--daemon/system_property_setter.cc32
-rw-r--r--daemon/system_property_setter.h52
-rw-r--r--daemon/system_property_setter_stub.cc37
-rw-r--r--daemon/system_property_setter_stub.h50
-rw-r--r--example/power_example.cc36
-rw-r--r--include/nativepower/constants.h5
-rw-r--r--include/nativepower/power_manager_client.h78
-rw-r--r--include/nativepower/power_manager_stub.h13
-rw-r--r--include/nativepower/wake_lock.h31
20 files changed, 658 insertions, 73 deletions
diff --git a/client/Android.mk b/client/Android.mk
index e2225df..be914b5 100644
--- a/client/Android.mk
+++ b/client/Android.mk
@@ -38,6 +38,7 @@ 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)
@@ -58,6 +59,7 @@ LOCAL_SHARED_LIBRARIES := \
libnativepower_test_support \
LOCAL_SRC_FILES := \
+ power_manager_client_unittest.cc \
wake_lock_unittest.cc \
include $(BUILD_NATIVE_TEST)
diff --git a/client/power_manager_client.cc b/client/power_manager_client.cc
new file mode 100644
index 0000000..6dd1a24
--- /dev/null
+++ b/client/power_manager_client.cc
@@ -0,0 +1,127 @@
+/*
+ * 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::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/client/power_manager_client_unittest.cc b/client/power_manager_client_unittest.cc
new file mode 100644
index 0000000..e3a6c70
--- /dev/null
+++ b/client/power_manager_client_unittest.cc
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <base/logging.h>
+#include <base/macros.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, 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/client/wake_lock.cc b/client/wake_lock.cc
index 98dcb0e..bf65b00 100644
--- a/client/wake_lock.cc
+++ b/client/wake_lock.cc
@@ -16,30 +16,29 @@
#include <nativepower/wake_lock.h>
-#include <base/bind.h>
#include <base/logging.h>
-#include <binder/IBinder.h>
#include <binderwrapper/binder_wrapper.h>
-#include <nativepower/constants.h>
+#include <nativepower/power_manager_client.h>
+#include <powermanager/IPowerManager.h>
#include <powermanager/PowerManager.h>
namespace android {
-// static
-std::unique_ptr<WakeLock> WakeLock::Create(const std::string& tag,
- const std::string& package) {
- std::unique_ptr<WakeLock> lock(new WakeLock(tag, package));
- if (!lock->Init())
- lock.reset();
- return lock;
+WakeLock::WakeLock(const std::string& tag,
+ const std::string& package,
+ PowerManagerClient* client)
+ : acquired_lock_(false),
+ tag_(tag),
+ package_(package),
+ client_(client) {
+ DCHECK(client_);
}
WakeLock::~WakeLock() {
- if (power_manager_.get()) {
- BinderWrapper::Get()->UnregisterForDeathNotifications(
- IInterface::asBinder(power_manager_));
+ sp<IPowerManager> power_manager = client_->power_manager();
+ if (acquired_lock_ && power_manager.get()) {
status_t status =
- power_manager_->releaseWakeLock(lock_binder_, 0 /* flags */);
+ power_manager->releaseWakeLock(lock_binder_, 0 /* flags */);
if (status != OK) {
LOG(ERROR) << "Wake lock release request for \"" << tag_ << "\" failed "
<< "with status " << status;
@@ -47,40 +46,26 @@ WakeLock::~WakeLock() {
}
}
-WakeLock::WakeLock(const std::string& tag, const std::string& package)
- : tag_(tag),
- package_(package) {}
-
bool WakeLock::Init() {
- sp<IBinder> power_manager_binder =
- BinderWrapper::Get()->GetService(kPowerManagerServiceName);
- if (!power_manager_binder.get()) {
- LOG(ERROR) << "Didn't get " << kPowerManagerServiceName << " service";
+ 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;
}
- power_manager_ = interface_cast<IPowerManager>(power_manager_binder);
- BinderWrapper::Get()->RegisterForDeathNotifications(
- power_manager_binder,
- base::Bind(&WakeLock::OnPowerManagerDied, base::Unretained(this)));
-
lock_binder_ = BinderWrapper::Get()->CreateLocalBinder();
- status_t status = power_manager_->acquireWakeLock(
+ status_t status = power_manager->acquireWakeLock(
POWERMANAGER_PARTIAL_WAKE_LOCK,
lock_binder_, String16(tag_.c_str()), String16(package_.c_str()));
if (status != OK) {
- LOG(ERROR) << "Wake lock acquire request for tag \"" << tag_ << "\" failed "
+ LOG(ERROR) << "Wake lock acquire request for \"" << tag_ << "\" failed "
<< "with status " << status;
- power_manager_.clear();
return false;
}
+ acquired_lock_ = true;
return true;
}
-void WakeLock::OnPowerManagerDied() {
- LOG(WARNING) << "Power manager died; lost wake lock for \"" << tag_ << "\"";
- power_manager_.clear();
-}
-
} // namespace android
diff --git a/client/wake_lock_unittest.cc b/client/wake_lock_unittest.cc
index 1221f1a..09f3dbf 100644
--- a/client/wake_lock_unittest.cc
+++ b/client/wake_lock_unittest.cc
@@ -16,12 +16,14 @@
#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>
@@ -32,21 +34,23 @@ class WakeLockTest : public BinderTestBase {
WakeLockTest()
: power_manager_(new PowerManagerStub()),
power_manager_binder_(power_manager_) {
- binder_wrapper_->SetBinderForService(kPowerManagerServiceName,
- power_manager_binder_);
+ 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) {
- std::unique_ptr<WakeLock> lock(WakeLock::Create("foo", "bar"));
+ std::unique_ptr<WakeLock> lock(client_.CreateWakeLock("foo", "bar"));
ASSERT_EQ(1u, power_manager_->num_locks());
ASSERT_EQ(1u, binder_wrapper()->local_binders().size());
EXPECT_EQ(
@@ -58,11 +62,11 @@ TEST_F(WakeLockTest, CreateAndDestroy) {
}
TEST_F(WakeLockTest, PowerManagerDeath) {
- std::unique_ptr<WakeLock> lock(WakeLock::Create("foo", "bar"));
+ std::unique_ptr<WakeLock> lock(client_.CreateWakeLock("foo", "bar"));
binder_wrapper()->NotifyAboutBinderDeath(power_manager_binder_);
- // Since the WakeLock was informed that the power manager died, it shouldn't
- // try to release its lock on destruction.
+ // Since PowerManagerClient was informed that the power manager died, WakeLock
+ // shouldn't try to release its lock on destruction.
lock.reset();
EXPECT_EQ(1u, power_manager_->num_locks());
}
diff --git a/daemon/Android.mk b/daemon/Android.mk
index 6677233..fdc18d4 100644
--- a/daemon/Android.mk
+++ b/daemon/Android.mk
@@ -22,6 +22,7 @@ nativepowerman_CommonCIncludes := $(LOCAL_PATH)/../include
nativepowerman_CommonSharedLibraries := \
libbinder \
libchrome \
+ libcutils \
libpowermanager \
libutils \
@@ -78,6 +79,7 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_SRC_FILES := \
BnPowerManager.cc \
power_manager.cc \
+ system_property_setter.cc \
wake_lock_manager.cc \
include $(BUILD_STATIC_LIBRARY)
@@ -97,6 +99,7 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_SRC_FILES := \
power_manager_unittest.cc \
+ system_property_setter_stub.cc \
wake_lock_manager_stub.cc \
wake_lock_manager_unittest.cc \
diff --git a/daemon/BnPowerManager.cc b/daemon/BnPowerManager.cc
index ed6b9e1..f3bf8bc 100644
--- a/daemon/BnPowerManager.cc
+++ b/daemon/BnPowerManager.cc
@@ -64,6 +64,32 @@ status_t BnPowerManager::onTransact(uint32_t code,
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);
}
diff --git a/daemon/power_manager.cc b/daemon/power_manager.cc
index 9247ecf..1c362f1 100644
--- a/daemon/power_manager.cc
+++ b/daemon/power_manager.cc
@@ -18,6 +18,7 @@
#include <base/logging.h>
#include <binderwrapper/binder_wrapper.h>
+#include <cutils/android_reboot.h>
#include <nativepower/constants.h>
#include <powermanager/IPowerManager.h>
#include <utils/Errors.h>
@@ -25,11 +26,16 @@
namespace android {
+const char PowerManager::kRebootPrefix[] = "reboot,";
+const char PowerManager::kShutdownPrefix[] = "shutdown,";
+
PowerManager::PowerManager() = default;
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())
@@ -79,20 +85,47 @@ status_t PowerManager::powerHint(int hintId, int data) {
}
status_t PowerManager::goToSleep(int64_t event_time_ms, int reason, int flags) {
+ NOTIMPLEMENTED() << "goToSleep: event_time_ms=" << event_time_ms
+ << " reason=" << reason << " flags=" << flags;
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;
}
diff --git a/daemon/power_manager.h b/daemon/power_manager.h
index 43ced8f..f4aa832 100644
--- a/daemon/power_manager.h
+++ b/daemon/power_manager.h
@@ -22,16 +22,29 @@
#include <base/macros.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[];
+
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);
@@ -72,6 +85,7 @@ class PowerManager : public BnPowerManager {
const String16& packageName,
int uid);
+ std::unique_ptr<SystemPropertySetterInterface> property_setter_;
std::unique_ptr<WakeLockManagerInterface> wake_lock_manager_;
DISALLOW_COPY_AND_ASSIGN(PowerManager);
diff --git a/daemon/power_manager_stub.cc b/daemon/power_manager_stub.cc
index 70ee877..f8c653e 100644
--- a/daemon/power_manager_stub.cc
+++ b/daemon/power_manager_stub.cc
@@ -106,12 +106,14 @@ status_t PowerManagerStub::goToSleep(int64_t event_time_ms,
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;
}
diff --git a/daemon/power_manager_unittest.cc b/daemon/power_manager_unittest.cc
index 45c5bc6..c09c297 100644
--- a/daemon/power_manager_unittest.cc
+++ b/daemon/power_manager_unittest.cc
@@ -19,11 +19,12 @@
#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 "wake_lock_manager.h"
+#include "system_property_setter_stub.h"
#include "wake_lock_manager_stub.h"
namespace android {
@@ -32,7 +33,11 @@ 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()) {
+ 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());
@@ -41,6 +46,8 @@ class PowerManagerTest : public BinderTestBase {
protected:
sp<PowerManager> power_manager_;
+ sp<IPowerManager> interface_;
+ SystemPropertySetterStub* property_setter_; // Owned by |power_manager_|.
WakeLockManagerStub* wake_lock_manager_; // Owned by |power_manager_|.
private:
@@ -54,16 +61,46 @@ TEST_F(PowerManagerTest, RegisterService) {
TEST_F(PowerManagerTest, AcquireAndReleaseWakeLock) {
sp<BBinder> binder = binder_wrapper()->CreateLocalBinder();
- EXPECT_EQ(OK,
- interface_cast<IPowerManager>(power_manager_)->acquireWakeLock(
- 0, binder, String16(), String16()));
+ EXPECT_EQ(OK, interface_->acquireWakeLock(0, binder, String16(), String16()));
ASSERT_EQ(1u, wake_lock_manager_->request_binders().size());
EXPECT_TRUE(wake_lock_manager_->has_request_binder(binder));
- EXPECT_EQ(OK,
- interface_cast<IPowerManager>(power_manager_)->releaseWakeLock(
- binder, 0));
+ EXPECT_EQ(OK, interface_->releaseWakeLock(binder, 0));
EXPECT_TRUE(wake_lock_manager_->request_binders().empty());
}
+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/daemon/system_property_setter.cc b/daemon/system_property_setter.cc
new file mode 100644
index 0000000..9368f54
--- /dev/null
+++ b/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/daemon/system_property_setter.h b/daemon/system_property_setter.h
new file mode 100644
index 0000000..8ccd2c3
--- /dev/null
+++ b/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/daemon/system_property_setter_stub.cc b/daemon/system_property_setter_stub.cc
new file mode 100644
index 0000000..d07212f
--- /dev/null
+++ b/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/daemon/system_property_setter_stub.h b/daemon/system_property_setter_stub.h
new file mode 100644
index 0000000..b84a72a
--- /dev/null
+++ b/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/example/power_example.cc b/example/power_example.cc
index 0ad9138..68134d7 100644
--- a/example/power_example.cc
+++ b/example/power_example.cc
@@ -23,25 +23,45 @@
#include <base/message_loop/message_loop.h>
#include <binderwrapper/binder_wrapper.h>
#include <chromeos/flag_helper.h>
+#include <nativepower/power_manager_client.h>
#include <nativepower/wake_lock.h>
-using android::BinderWrapper;
-using android::WakeLock;
+namespace {
+
+// Seconds to sleep after acquiring a wake lock.
+const int kWakeLockSleepSec = 5;
+
+} // namespace
int main(int argc, char *argv[]) {
- DEFINE_int32(sleep_sec, 5, "Number of seconds to sleep");
+ DEFINE_string(action, "",
+ "Action to perform (\"reboot\", \"shut_down\", \"wake_lock\")");
chromeos::FlagHelper::Init(argc, argv, "Example power-management client.");
logging::InitLogging(logging::LoggingSettings());
base::AtExitManager at_exit;
base::MessageLoopForIO loop;
- BinderWrapper::Create();
+ android::BinderWrapper::Create();
- LOG(INFO) << "Creating wake lock";
- std::unique_ptr<WakeLock> lock(WakeLock::Create("power_example", "power"));
+ android::PowerManagerClient client;
+ CHECK(client.Init());
- LOG(INFO) << "Sleeping for " << FLAGS_sleep_sec << " seconds";
- sleep(FLAGS_sleep_sec);
+ 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 == "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/include/nativepower/constants.h b/include/nativepower/constants.h
index ddeb3d7..9ceeb40 100644
--- a/include/nativepower/constants.h
+++ b/include/nativepower/constants.h
@@ -22,6 +22,11 @@ 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/include/nativepower/power_manager_client.h b/include/nativepower/power_manager_client.h
new file mode 100644
index 0000000..a7053c7
--- /dev/null
+++ b/include/nativepower/power_manager_client.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+
+#include <base/macros.h>
+#include <base/memory/weak_ptr.h>
+#include <nativepower/wake_lock.h>
+#include <powermanager/IPowerManager.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+// 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);
+
+ // Shuts down or reboots the system.
+ 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/include/nativepower/power_manager_stub.h b/include/nativepower/power_manager_stub.h
index 7e4be06..966407c 100644
--- a/include/nativepower/power_manager_stub.h
+++ b/include/nativepower/power_manager_stub.h
@@ -16,6 +16,7 @@
#include <map>
#include <string>
+#include <vector>
#include <base/macros.h>
#include <nativepower/BnPowerManager.h>
@@ -36,6 +37,13 @@ class PowerManagerStub : public BnPowerManager {
size_t num_locks() const { return locks_.size(); }
+ const std::vector<std::string>& reboot_reasons() const {
+ return reboot_reasons_;
+ }
+ const std::vector<std::string>& shutdown_reasons() const {
+ return shutdown_reasons_;
+ }
+
// Returns a string describing the lock registered for |binder|, or an empty
// string if no lock is present.
std::string GetLockString(const sp<IBinder>& binder) const;
@@ -85,6 +93,11 @@ class PowerManagerStub : public BnPowerManager {
using LockInfoMap = std::map<sp<IBinder>, LockInfo>;
LockInfoMap locks_;
+ // 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);
};
diff --git a/include/nativepower/wake_lock.h b/include/nativepower/wake_lock.h
index 6fc0782..faa9d8a 100644
--- a/include/nativepower/wake_lock.h
+++ b/include/nativepower/wake_lock.h
@@ -17,45 +17,42 @@
#ifndef SYSTEM_NATIVEPOWER_INCLUDE_NATIVEPOWER_WAKE_LOCK_H_
#define SYSTEM_NATIVEPOWER_INCLUDE_NATIVEPOWER_WAKE_LOCK_H_
-#include <memory>
#include <string>
#include <base/macros.h>
-#include <powermanager/IPowerManager.h>
#include <utils/StrongPointer.h>
namespace android {
class IBinder;
+class PowerManagerClient;
-// RAII-style object that prevents the system from suspending.
+// RAII-style class that prevents the system from suspending.
//
-// android::BinderWrapper must be initialized before constructing this class.
+// Instantiate by calling PowerManagerClient::CreateWakeLock().
class WakeLock {
public:
- // Creates and returns a wake lock identified by |tag| and |package|.
- // An empty pointer is returned on failure (e.g. due to issues communicating
- // with the power manager).
- static std::unique_ptr<WakeLock> Create(const std::string& tag,
- const std::string& package);
-
~WakeLock();
private:
- // Called by Create().
- WakeLock(const std::string& tag, const std::string& package);
+ 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 returns true on success. Called by Create().
+ // Initializes the object and acquires the lock, returning true on success.
bool Init();
- // Called by |death_recipient_| in response to |power_manager_| dying.
- void OnPowerManagerDied();
+ // Was a lock successfully acquired from the power manager?
+ bool acquired_lock_;
std::string tag_;
std::string package_;
- // Interface for communicating with the power manager.
- sp<IPowerManager> power_manager_;
+ // Weak pointer to the client that created this wake lock.
+ PowerManagerClient* client_;
// Locally-created binder passed to the power manager.
sp<IBinder> lock_binder_;