diff options
author | Daniel Erat <derat@google.com> | 2015-09-30 17:04:48 -0600 |
---|---|---|
committer | Daniel Erat <derat@google.com> | 2015-10-02 16:07:17 -0600 |
commit | c2a4b05a931fbf3ecbf1915049b549b33dae8ba5 (patch) | |
tree | 09f634d0354560e0576b9b774fd8910ad14fce7b | |
parent | 77ca78c8d297564db431a5b3a9165e170bb7c72a (diff) | |
download | nativepower-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.mk | 2 | ||||
-rw-r--r-- | client/power_manager_client.cc | 127 | ||||
-rw-r--r-- | client/power_manager_client_unittest.cc | 68 | ||||
-rw-r--r-- | client/wake_lock.cc | 55 | ||||
-rw-r--r-- | client/wake_lock_unittest.cc | 16 | ||||
-rw-r--r-- | daemon/Android.mk | 3 | ||||
-rw-r--r-- | daemon/BnPowerManager.cc | 26 | ||||
-rw-r--r-- | daemon/power_manager.cc | 33 | ||||
-rw-r--r-- | daemon/power_manager.h | 14 | ||||
-rw-r--r-- | daemon/power_manager_stub.cc | 2 | ||||
-rw-r--r-- | daemon/power_manager_unittest.cc | 51 | ||||
-rw-r--r-- | daemon/system_property_setter.cc | 32 | ||||
-rw-r--r-- | daemon/system_property_setter.h | 52 | ||||
-rw-r--r-- | daemon/system_property_setter_stub.cc | 37 | ||||
-rw-r--r-- | daemon/system_property_setter_stub.h | 50 | ||||
-rw-r--r-- | example/power_example.cc | 36 | ||||
-rw-r--r-- | include/nativepower/constants.h | 5 | ||||
-rw-r--r-- | include/nativepower/power_manager_client.h | 78 | ||||
-rw-r--r-- | include/nativepower/power_manager_stub.h | 13 | ||||
-rw-r--r-- | include/nativepower/wake_lock.h | 31 |
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_; |