Commit b651946e authored by chirantan's avatar chirantan Committed by Commit bot

chromeos: power: Refactor RendererFreezer and add tests

Refactor the RendererFreezer class so that untestable code is moved into
a delegate and add unit tests.  Modify FakePowerManagerClient so that it
provides more information for tests.

Also use a CancelableClosure for the asynchronous suspend readiness
callback in case we get a SuspendDone before we've had a chance to run
OnReadyForSuspend().

BUG=364339,414396
Signed-off-by: default avatarChirantan Ekbote <chirantan@chromium.org>

Review URL: https://codereview.chromium.org/543303002

Cr-Commit-Position: refs/heads/master@{#295111}
parent abaa1bf6
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
#include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h" #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h"
#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
#include "chrome/browser/chromeos/policy/device_local_account.h" #include "chrome/browser/chromeos/policy/device_local_account.h"
#include "chrome/browser/chromeos/power/freezer_cgroup_process_manager.h"
#include "chrome/browser/chromeos/power/idle_action_warning_observer.h" #include "chrome/browser/chromeos/power/idle_action_warning_observer.h"
#include "chrome/browser/chromeos/power/light_bar.h" #include "chrome/browser/chromeos/power/light_bar.h"
#include "chrome/browser/chromeos/power/peripheral_battery_observer.h" #include "chrome/browser/chromeos/power/peripheral_battery_observer.h"
...@@ -562,7 +563,9 @@ void ChromeBrowserMainPartsChromeos::PostProfileInit() { ...@@ -562,7 +563,9 @@ void ChromeBrowserMainPartsChromeos::PostProfileInit() {
peripheral_battery_observer_.reset(new PeripheralBatteryObserver()); peripheral_battery_observer_.reset(new PeripheralBatteryObserver());
renderer_freezer_.reset(new RendererFreezer()); renderer_freezer_.reset(
new RendererFreezer(scoped_ptr<RendererFreezer::Delegate>(
new FreezerCgroupProcessManager())));
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kWakeOnPackets)) if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kWakeOnPackets))
light_bar_.reset(new LightBar()); light_bar_.reset(new LightBar());
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/power/freezer_cgroup_process_manager.h"
#include <string>
#include "base/files/file_util.h"
#include "base/logging.h"
namespace chromeos {
namespace {
const char kFreezerStatePath[] =
"/sys/fs/cgroup/freezer/chrome_renderers/freezer.state";
const char kFreezeCommand[] = "FROZEN";
const char kThawCommand[] = "THAWED";
} // namespace
FreezerCgroupProcessManager::FreezerCgroupProcessManager()
: state_path_(base::FilePath(kFreezerStatePath)),
enabled_(base::PathIsWritable(state_path_)) {
if (!enabled_) {
LOG(WARNING) << "Cgroup freezer does not exist or is not writable. "
<< "Unable to freeze renderer processes.";
}
}
FreezerCgroupProcessManager::~FreezerCgroupProcessManager() {
}
bool FreezerCgroupProcessManager::FreezeRenderers() {
if (!enabled_) {
LOG(ERROR) << "Attempting to freeze renderers when the freezer cgroup is "
<< "not available.";
return false;
}
return WriteCommandToStateFile(kFreezeCommand);
}
bool FreezerCgroupProcessManager::ThawRenderers() {
if (!enabled_) {
LOG(ERROR) << "Attempting to thaw renderers when the freezer cgroup is not "
<< "available.";
return false;
}
return WriteCommandToStateFile(kThawCommand);
}
bool FreezerCgroupProcessManager::CanFreezeRenderers() {
return enabled_;
}
bool FreezerCgroupProcessManager::WriteCommandToStateFile(
const std::string& command) {
int bytes = base::WriteFile(state_path_, command.c_str(), command.size());
if (bytes == -1) {
PLOG(ERROR) << "Writing " << command << " to " << state_path_.value()
<< " failed";
return false;
} else if (bytes != static_cast<int>(command.size())) {
LOG(ERROR) << "Only wrote " << bytes << " byte(s) when writing "
<< command << " to " << state_path_.value();
return false;
}
return true;
}
} // namespace chromeos
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_POWER_FREEZER_CGROUP_PROCESS_MANAGER_H_
#define CHROME_BROWSER_CHROMEOS_POWER_FREEZER_CGROUP_PROCESS_MANAGER_H_
#include "base/files/file_path.h"
#include "base/macros.h"
#include "chrome/browser/chromeos/power/renderer_freezer.h"
namespace chromeos {
// Manages all the processes in the freezer cgroup on Chrome OS.
class FreezerCgroupProcessManager : public RendererFreezer::Delegate {
public:
FreezerCgroupProcessManager();
virtual ~FreezerCgroupProcessManager();
// RendererFreezer::Delegate overrides.
virtual bool FreezeRenderers() OVERRIDE;
virtual bool ThawRenderers() OVERRIDE;
virtual bool CanFreezeRenderers() OVERRIDE;
private:
bool WriteCommandToStateFile(const std::string& command);
base::FilePath state_path_;
bool enabled_;
DISALLOW_COPY_AND_ASSIGN(FreezerCgroupProcessManager);
};
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_POWER_FREEZER_CGROUP_PROCESS_MANAGER_H_
...@@ -4,87 +4,67 @@ ...@@ -4,87 +4,67 @@
#include "chrome/browser/chromeos/power/renderer_freezer.h" #include "chrome/browser/chromeos/power/renderer_freezer.h"
#include <cstring> // needed for strlen()
#include "base/bind.h" #include "base/bind.h"
#include "base/files/file_util.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dbus_thread_manager.h"
namespace chromeos { namespace chromeos {
namespace { RendererFreezer::RendererFreezer(scoped_ptr<RendererFreezer::Delegate> delegate)
const char kFreezerStatePath[] = : frozen_(false),
"/sys/fs/cgroup/freezer/chrome_renderers/freezer.state"; delegate_(delegate.Pass()),
const char kFreezeCommand[] = "FROZEN"; weak_factory_(this) {
const char kThawCommand[] = "THAWED"; if (delegate_->CanFreezeRenderers())
DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
}
} // namespace RendererFreezer::~RendererFreezer() {
if (delegate_->CanFreezeRenderers())
DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
}
void RendererFreezer::SuspendImminent() { void RendererFreezer::SuspendImminent() {
// SuspendImminent() might end up being called multiple times before we run // If there was already a callback pending, this will cancel it and create a
// OnReadyToSuspend() (crbug.com/414396). In case a callback is already // new one.
// pending, we only store the new callback and do nothing else. suspend_readiness_callback_.Reset(
if (suspend_readiness_callback_.is_null()) { base::Bind(&RendererFreezer::OnReadyToSuspend,
// There is no callback pending so post the task. weak_factory_.GetWeakPtr(),
base::MessageLoop::current()->PostTask( DBusThreadManager::Get()
FROM_HERE, ->GetPowerManagerClient()
base::Bind(&RendererFreezer::OnReadyToSuspend, ->GetSuspendReadinessCallback()));
weak_factory_.GetWeakPtr()));
} base::MessageLoop::current()->PostTask(
FROM_HERE, suspend_readiness_callback_.callback());
// Always update the callback because only the most recent one matters.
suspend_readiness_callback_ = DBusThreadManager::Get()
->GetPowerManagerClient()
->GetSuspendReadinessCallback();
} }
void RendererFreezer::SuspendDone(const base::TimeDelta& sleep_duration) { void RendererFreezer::SuspendDone(const base::TimeDelta& sleep_duration) {
// If we get a SuspendDone before we've had a chance to run OnReadyForSuspend,
// we should cancel it because we no longer want to freeze the renderers. If
// we've already run it then cancelling the callback shouldn't really make a
// difference.
suspend_readiness_callback_.Cancel();
if (!frozen_) if (!frozen_)
return; return;
if (base::WriteFile(state_path_, kThawCommand, strlen(kThawCommand)) != if (!delegate_->ThawRenderers()) {
static_cast<int>(strlen(kThawCommand))) {
// We failed to write the thaw command and the renderers are still frozen. // We failed to write the thaw command and the renderers are still frozen.
// We are in big trouble because none of the tabs will be responsive so // We are in big trouble because none of the tabs will be responsive so
// let's crash the browser instead. // let's crash the browser instead.
PLOG(FATAL) << "Unable to thaw processes in the cgroup freezer."; LOG(FATAL) << "Unable to thaw renderers.";
} }
frozen_ = false; frozen_ = false;
} }
void RendererFreezer::OnReadyToSuspend() { void RendererFreezer::OnReadyToSuspend(
if (base::WriteFile(state_path_, kFreezeCommand, strlen(kFreezeCommand)) != const base::Closure& power_manager_callback) {
static_cast<int>(strlen(kFreezeCommand))) { if (delegate_->FreezeRenderers())
PLOG(WARNING) << "Unable to freeze processes in the cgroup freezer.";
} else {
frozen_ = true; frozen_ = true;
}
CHECK(!suspend_readiness_callback_.is_null()); // crbug.com/414396
suspend_readiness_callback_.Run();
suspend_readiness_callback_.Reset();
}
RendererFreezer::RendererFreezer()
: state_path_(base::FilePath(kFreezerStatePath)),
enabled_(base::PathExists(state_path_) &&
base::PathIsWritable(state_path_)),
frozen_(false),
weak_factory_(this) {
if (enabled_) {
DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
} else {
LOG(WARNING) << "Cgroup freezer does not exist or is not writable. "
<< "Processes will not be frozen during suspend.";
}
}
RendererFreezer::~RendererFreezer() { DCHECK(!power_manager_callback.is_null());
if (enabled_) power_manager_callback.Run();
DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
} }
} // namespace chromeos } // namespace chromeos
...@@ -6,7 +6,9 @@ ...@@ -6,7 +6,9 @@
#define CHROME_BROWSER_CHROMEOS_POWER_RENDERER_FREEZER_H_ #define CHROME_BROWSER_CHROMEOS_POWER_RENDERER_FREEZER_H_
#include "base/callback.h" #include "base/callback.h"
#include "base/files/file_path.h" #include "base/cancelable_callback.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "chromeos/chromeos_export.h" #include "chromeos/chromeos_export.h"
...@@ -20,7 +22,23 @@ namespace chromeos { ...@@ -20,7 +22,23 @@ namespace chromeos {
// destruction. // destruction.
class CHROMEOS_EXPORT RendererFreezer : public PowerManagerClient::Observer { class CHROMEOS_EXPORT RendererFreezer : public PowerManagerClient::Observer {
public: public:
RendererFreezer(); class Delegate {
public:
virtual ~Delegate() {}
// Freezes the chrome renderers. Returns true if the operation was
// successful.
virtual bool FreezeRenderers() = 0;
// Thaws the chrome renderers. Returns true if the operation was
// successful.
virtual bool ThawRenderers() = 0;
// Returns true iff the delegate is capable of freezing renderers.
virtual bool CanFreezeRenderers() = 0;
};
explicit RendererFreezer(scoped_ptr<Delegate> delegate);
virtual ~RendererFreezer(); virtual ~RendererFreezer();
// PowerManagerClient::Observer implementation // PowerManagerClient::Observer implementation
...@@ -28,14 +46,15 @@ class CHROMEOS_EXPORT RendererFreezer : public PowerManagerClient::Observer { ...@@ -28,14 +46,15 @@ class CHROMEOS_EXPORT RendererFreezer : public PowerManagerClient::Observer {
virtual void SuspendDone(const base::TimeDelta& sleep_duration) OVERRIDE; virtual void SuspendDone(const base::TimeDelta& sleep_duration) OVERRIDE;
private: private:
void OnReadyToSuspend(); // Called when all asynchronous work is complete and renderers can be frozen.
void OnReadyToSuspend(const base::Closure& power_manager_callback);
// Used to ensure that renderers do not get frozen if the suspend is canceled.
base::CancelableClosure suspend_readiness_callback_;
base::FilePath state_path_;
bool enabled_;
bool frozen_; bool frozen_;
// Callback used to asynchronously report suspend readiness. scoped_ptr<Delegate> delegate_;
base::Closure suspend_readiness_callback_;
base::WeakPtrFactory<RendererFreezer> weak_factory_; base::WeakPtrFactory<RendererFreezer> weak_factory_;
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/power/renderer_freezer.h"
#include <string>
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/fake_power_manager_client.h"
#include "testing/gtest/include/gtest/gtest-death-test.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace {
// Class that delegates used in testing can inherit from to record calls that
// are made by the code being tested.
class ActionRecorder {
public:
ActionRecorder() {}
virtual ~ActionRecorder() {}
// Returns a comma-separated string describing the actions that were
// requested since the previous call to GetActions() (i.e. results are
// non-repeatable).
std::string GetActions() {
std::string actions = actions_;
actions_.clear();
return actions;
}
protected:
// Appends |new_action| to |actions_|, using a comma as a separator if
// other actions are already listed.
void AppendAction(const std::string& new_action) {
if (!actions_.empty())
actions_ += ",";
actions_ += new_action;
}
private:
// Comma-separated list of actions that have been performed.
std::string actions_;
DISALLOW_COPY_AND_ASSIGN(ActionRecorder);
};
// Actions that can be returned by TestDelegate::GetActions().
const char kFreezeRenderers[] = "freeze_renderers";
const char kThawRenderers[] = "thaw_renderers";
const char kNoActions[] = "";
// Test implementation of RendererFreezer::Delegate that records the actions it
// was asked to perform.
class TestDelegate : public RendererFreezer::Delegate, public ActionRecorder {
public:
TestDelegate()
: can_freeze_renderers_(true),
freeze_renderers_result_(true),
thaw_renderers_result_(true) {}
virtual ~TestDelegate() {}
// RendererFreezer::Delegate overrides.
virtual bool FreezeRenderers() OVERRIDE {
AppendAction(kFreezeRenderers);
return freeze_renderers_result_;
}
virtual bool ThawRenderers() OVERRIDE {
AppendAction(kThawRenderers);
return thaw_renderers_result_;
}
virtual bool CanFreezeRenderers() OVERRIDE { return can_freeze_renderers_; }
void set_freeze_renderers_result(bool result) {
freeze_renderers_result_ = result;
}
void set_thaw_renderers_result(bool result) {
thaw_renderers_result_ = result;
}
// Sets whether the delegate is capable of freezing renderers. This also
// changes |freeze_renderers_result_| and |thaw_renderers_result_|.
void set_can_freeze_renderers(bool can_freeze) {
can_freeze_renderers_ = can_freeze;
// If the delegate cannot freeze renderers, then the result of trying to do
// so will be false.
freeze_renderers_result_ = can_freeze;
thaw_renderers_result_ = can_freeze;
}
private:
bool can_freeze_renderers_;
bool freeze_renderers_result_;
bool thaw_renderers_result_;
DISALLOW_COPY_AND_ASSIGN(TestDelegate);
};
} // namespace
class RendererFreezerTest : public testing::Test {
public:
RendererFreezerTest()
: power_manager_client_(new FakePowerManagerClient()),
test_delegate_(new TestDelegate()) {
DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient(
scoped_ptr<PowerManagerClient>(power_manager_client_));
}
virtual ~RendererFreezerTest() {
renderer_freezer_.reset();
DBusThreadManager::Shutdown();
}
void Init() {
renderer_freezer_.reset(new RendererFreezer(
scoped_ptr<RendererFreezer::Delegate>(test_delegate_)));
}
protected:
FakePowerManagerClient* power_manager_client_;
TestDelegate* test_delegate_;
scoped_ptr<RendererFreezer> renderer_freezer_;
private:
base::MessageLoop message_loop_;
DISALLOW_COPY_AND_ASSIGN(RendererFreezerTest);
};
// Tests that the RendererFreezer freezes renderers on suspend and thaws them on
// resume.
TEST_F(RendererFreezerTest, SuspendResume) {
Init();
power_manager_client_->SendSuspendImminent();
// The RendererFreezer should have grabbed an asynchronous callback and done
// nothing else.
EXPECT_EQ(1, power_manager_client_->GetNumPendingSuspendReadinessCallbacks());
EXPECT_EQ(kNoActions, test_delegate_->GetActions());
// The RendererFreezer should eventually freeze the renderers and run the
// callback.
base::RunLoop().RunUntilIdle();
EXPECT_EQ(0, power_manager_client_->GetNumPendingSuspendReadinessCallbacks());
EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions());
// The renderers should be thawed when we resume.
power_manager_client_->SendSuspendDone();
EXPECT_EQ(kThawRenderers, test_delegate_->GetActions());
}
// Tests that the RendereFreezer doesn't freeze renderers if the suspend attempt
// was canceled before it had a chance to complete.
TEST_F(RendererFreezerTest, SuspendCanceled) {
Init();
// We shouldn't do anything yet.
power_manager_client_->SendSuspendImminent();
EXPECT_EQ(kNoActions, test_delegate_->GetActions());
// If a suspend gets canceled for any reason, we should see a SuspendDone().
power_manager_client_->SendSuspendDone();
// We shouldn't try to freeze the renderers now.
base::RunLoop().RunUntilIdle();
EXPECT_EQ(kNoActions, test_delegate_->GetActions());
}
// Tests that the renderer freezer does nothing if the delegate cannot freeze
// renderers.
TEST_F(RendererFreezerTest, DelegateCannotFreezeRenderers) {
test_delegate_->set_can_freeze_renderers(false);
Init();
power_manager_client_->SendSuspendImminent();
// The RendererFreezer should not have grabbed a callback or done anything
// else.
EXPECT_EQ(0, power_manager_client_->GetNumPendingSuspendReadinessCallbacks());
EXPECT_EQ(kNoActions, test_delegate_->GetActions());
// There should be nothing in the message loop.
base::RunLoop().RunUntilIdle();
EXPECT_EQ(kNoActions, test_delegate_->GetActions());
// Nothing happens on resume.
power_manager_client_->SendSuspendDone();
EXPECT_EQ(kNoActions, test_delegate_->GetActions());
}
// Tests that the RendererFreezer does nothing on resume if the freezing
// operation was unsuccessful.
TEST_F(RendererFreezerTest, ErrorFreezingRenderers) {
Init();
test_delegate_->set_freeze_renderers_result(false);
power_manager_client_->SendSuspendImminent();
EXPECT_EQ(1, power_manager_client_->GetNumPendingSuspendReadinessCallbacks());
// The freezing operation should fail, but we should still report readiness.
base::RunLoop().RunUntilIdle();
EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions());
EXPECT_EQ(0, power_manager_client_->GetNumPendingSuspendReadinessCallbacks());
// Since the delegate reported that the freezing was unsuccessful, don't do
// anything on resume.
power_manager_client_->SendSuspendDone();
EXPECT_EQ(kNoActions, test_delegate_->GetActions());
}
#if defined(GTEST_HAS_DEATH_TEST)
// Tests that the RendererFreezer crashes the browser if the freezing operation
// was successful but the thawing operation failed.
TEST_F(RendererFreezerTest, ErrorThawingRenderers) {
Init();
test_delegate_->set_thaw_renderers_result(false);
power_manager_client_->SendSuspendImminent();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions());
EXPECT_DEATH(power_manager_client_->SendSuspendDone(), "Unable to thaw");
}
#endif // GTEST_HAS_DEATH_TEST
} // namespace chromeos
...@@ -901,6 +901,8 @@ ...@@ -901,6 +901,8 @@
'browser/chromeos/policy/wildcard_login_checker.h', 'browser/chromeos/policy/wildcard_login_checker.h',
'browser/chromeos/power/cpu_data_collector.cc', 'browser/chromeos/power/cpu_data_collector.cc',
'browser/chromeos/power/cpu_data_collector.h', 'browser/chromeos/power/cpu_data_collector.h',
'browser/chromeos/power/freezer_cgroup_process_manager.cc',
'browser/chromeos/power/freezer_cgroup_process_manager.h',
'browser/chromeos/power/idle_action_warning_dialog_view.cc', 'browser/chromeos/power/idle_action_warning_dialog_view.cc',
'browser/chromeos/power/idle_action_warning_dialog_view.h', 'browser/chromeos/power/idle_action_warning_dialog_view.h',
'browser/chromeos/power/idle_action_warning_observer.cc', 'browser/chromeos/power/idle_action_warning_observer.cc',
......
...@@ -235,6 +235,7 @@ ...@@ -235,6 +235,7 @@
'browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc', 'browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc',
'browser/chromeos/power/power_data_collector_unittest.cc', 'browser/chromeos/power/power_data_collector_unittest.cc',
'browser/chromeos/power/power_prefs_unittest.cc', 'browser/chromeos/power/power_prefs_unittest.cc',
'browser/chromeos/power/renderer_freezer_unittest.cc',
'browser/chromeos/preferences_unittest.cc', 'browser/chromeos/preferences_unittest.cc',
'browser/chromeos/profiles/profile_list_chromeos_unittest.cc', 'browser/chromeos/profiles/profile_list_chromeos_unittest.cc',
'browser/chromeos/proxy_config_service_impl_unittest.cc', 'browser/chromeos/proxy_config_service_impl_unittest.cc',
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "chromeos/dbus/fake_power_manager_client.h" #include "chromeos/dbus/fake_power_manager_client.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "chromeos/dbus/power_manager/policy.pb.h" #include "chromeos/dbus/power_manager/policy.pb.h"
...@@ -14,6 +16,7 @@ FakePowerManagerClient::FakePowerManagerClient() ...@@ -14,6 +16,7 @@ FakePowerManagerClient::FakePowerManagerClient()
num_request_shutdown_calls_(0), num_request_shutdown_calls_(0),
num_set_policy_calls_(0), num_set_policy_calls_(0),
num_set_is_projecting_calls_(0), num_set_is_projecting_calls_(0),
num_pending_suspend_readiness_callbacks_(0),
is_projecting_(false) { is_projecting_(false) {
} }
...@@ -85,11 +88,14 @@ void FakePowerManagerClient::SetIsProjecting(bool is_projecting) { ...@@ -85,11 +88,14 @@ void FakePowerManagerClient::SetIsProjecting(bool is_projecting) {
} }
base::Closure FakePowerManagerClient::GetSuspendReadinessCallback() { base::Closure FakePowerManagerClient::GetSuspendReadinessCallback() {
return base::Closure(); ++num_pending_suspend_readiness_callbacks_;
return base::Bind(&FakePowerManagerClient::HandleSuspendReadiness,
base::Unretained(this));
} }
int FakePowerManagerClient::GetNumPendingSuspendReadinessCallbacks() { int FakePowerManagerClient::GetNumPendingSuspendReadinessCallbacks() {
return 0; return num_pending_suspend_readiness_callbacks_;
} }
void FakePowerManagerClient::SendSuspendImminent() { void FakePowerManagerClient::SendSuspendImminent() {
...@@ -111,4 +117,10 @@ void FakePowerManagerClient::SendPowerButtonEvent( ...@@ -111,4 +117,10 @@ void FakePowerManagerClient::SendPowerButtonEvent(
PowerButtonEventReceived(down, timestamp)); PowerButtonEventReceived(down, timestamp));
} }
void FakePowerManagerClient::HandleSuspendReadiness() {
CHECK(num_pending_suspend_readiness_callbacks_ > 0);
--num_pending_suspend_readiness_callbacks_;
}
} // namespace chromeos } // namespace chromeos
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <string> #include <string>
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/macros.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "chromeos/dbus/power_manager/policy.pb.h" #include "chromeos/dbus/power_manager/policy.pb.h"
#include "chromeos/dbus/power_manager/suspend.pb.h" #include "chromeos/dbus/power_manager/suspend.pb.h"
...@@ -67,6 +68,10 @@ class FakePowerManagerClient : public PowerManagerClient { ...@@ -67,6 +68,10 @@ class FakePowerManagerClient : public PowerManagerClient {
void SendPowerButtonEvent(bool down, const base::TimeTicks& timestamp); void SendPowerButtonEvent(bool down, const base::TimeTicks& timestamp);
private: private:
// Callback that will be run by asynchronous suspend delays to report
// readiness.
void HandleSuspendReadiness();
ObserverList<Observer> observers_; ObserverList<Observer> observers_;
// Last policy passed to SetPolicy(). // Last policy passed to SetPolicy().
...@@ -78,6 +83,9 @@ class FakePowerManagerClient : public PowerManagerClient { ...@@ -78,6 +83,9 @@ class FakePowerManagerClient : public PowerManagerClient {
int num_set_policy_calls_; int num_set_policy_calls_;
int num_set_is_projecting_calls_; int num_set_is_projecting_calls_;
// Number of pending suspend readiness callbacks.
int num_pending_suspend_readiness_callbacks_;
// Last projecting state set in SetIsProjecting(). // Last projecting state set in SetIsProjecting().
bool is_projecting_; bool is_projecting_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment