summaryrefslogtreecommitdiffstats
path: root/chromeos
diff options
context:
space:
mode:
authormarcheu@chromium.org <marcheu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-23 01:46:59 +0000
committermarcheu@chromium.org <marcheu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-23 01:46:59 +0000
commit71f77244e169d31ab29246d1bfe80c62cbfe25e4 (patch)
treeb98bc3bfff504f0e5cb469d7a779ab398764f4df /chromeos
parent1867c74baef366abf533d89ccddfef00af1a7a46 (diff)
downloadchromium_src-71f77244e169d31ab29246d1bfe80c62cbfe25e4.zip
chromium_src-71f77244e169d31ab29246d1bfe80c62cbfe25e4.tar.gz
chromium_src-71f77244e169d31ab29246d1bfe80c62cbfe25e4.tar.bz2
Implement support for monitor suspend.
This speeds up idle resume by around 2.5 seconds. Previously, we would turn the panel off before idle suspend. Then we would suspend and resume. On resume, the kernel would restore the "off" state, and the Chrome monitor code would kick in to turn the panel on. This is a huge waste of time when each panel configuration step takes more than one second. Instead, just before suspending, we turn the backlight off and the panel on. On resume the kernel sets the panel state to on right away, and power_manager turns the backlight on. The Chrome monitor code still runs, but is a noop. This change needs this power_manager change to handle the backlight part: https://gerrit.chromium.org/gerrit/#/c/40971/ BUG=chrome-os-partner:13364 TEST=By hand: reduce the idle suspend timeout, let the machine idle and TEST=suspend, press a key to resume and see how long it takes. The time TEST=it takes shrinks from ~4 seconds to ~1.5 second. Change-Id: I610995c12ed08624eb0bc91057d7c9bfa8002fbf Review URL: https://chromiumcodereview.appspot.com/11783020 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@178195 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chromeos')
-rw-r--r--chromeos/dbus/power_manager_client.cc111
-rw-r--r--chromeos/dbus/power_manager_client.h4
-rw-r--r--chromeos/display/output_configurator.cc15
-rw-r--r--chromeos/display/output_configurator.h5
4 files changed, 133 insertions, 2 deletions
diff --git a/chromeos/dbus/power_manager_client.cc b/chromeos/dbus/power_manager_client.cc
index 4dd191f..04a6507 100644
--- a/chromeos/dbus/power_manager_client.cc
+++ b/chromeos/dbus/power_manager_client.cc
@@ -27,11 +27,15 @@
namespace chromeos {
+const int kSuspendDelayTimeoutMs = 5000;
+
// The PowerManagerClient implementation used in production.
class PowerManagerClientImpl : public PowerManagerClient {
public:
explicit PowerManagerClientImpl(dbus::Bus* bus)
: power_manager_proxy_(NULL),
+ suspend_delay_id_(-1),
+ has_suspend_delay_id_(false),
weak_ptr_factory_(this) {
power_manager_proxy_ = bus->GetObjectProxy(
power_manager::kPowerManagerServiceName,
@@ -96,9 +100,57 @@ class PowerManagerClientImpl : public PowerManagerClient {
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&PowerManagerClientImpl::SignalConnected,
weak_ptr_factory_.GetWeakPtr()));
+
+ power_manager_proxy_->ConnectToSignal(
+ power_manager::kPowerManagerInterface,
+ power_manager::kSuspendImminentSignal,
+ base::Bind(
+ &PowerManagerClientImpl::SuspendImminentReceived,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&PowerManagerClientImpl::SignalConnected,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ // Register to powerd for suspend notifications.
+ dbus::MethodCall method_call(
+ power_manager::kPowerManagerInterface,
+ power_manager::kRegisterSuspendDelayMethod);
+ dbus::MessageWriter writer(&method_call);
+
+ power_manager::RegisterSuspendDelayRequest protobuf_request;
+ base::TimeDelta timeout =
+ base::TimeDelta::FromMilliseconds(kSuspendDelayTimeoutMs);
+ protobuf_request.set_timeout(timeout.ToInternalValue());
+
+ if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) {
+ LOG(ERROR) << "Error constructing message for "
+ << power_manager::kRegisterSuspendDelayMethod;
+ return;
+ }
+ power_manager_proxy_->CallMethod(
+ &method_call,
+ dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(
+ &PowerManagerClientImpl::OnRegisterSuspendDelayReply,
+ weak_ptr_factory_.GetWeakPtr()));
}
virtual ~PowerManagerClientImpl() {
+ // Unregister from powerd for suspend notifications.
+ if (has_suspend_delay_id_) {
+ dbus::MethodCall method_call(
+ power_manager::kPowerManagerInterface,
+ power_manager::kUnregisterSuspendDelayMethod);
+ dbus::MessageWriter writer(&method_call);
+
+ power_manager::UnregisterSuspendDelayRequest protobuf;
+ protobuf.Clear();
+ protobuf.set_delay_id(suspend_delay_id_);
+
+ power_manager_proxy_->CallMethod(
+ &method_call,
+ dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ dbus::ObjectProxy::EmptyResponseCallback());
+ }
}
// PowerManagerClient overrides:
@@ -444,6 +496,23 @@ class PowerManagerClientImpl : public PowerManagerClient {
callback.Run(percent);
}
+ void OnRegisterSuspendDelayReply(dbus::Response* response) {
+ if (!response) {
+ LOG(ERROR) << "Error calling "
+ << power_manager::kRegisterSuspendDelayMethod;
+ return;
+ }
+ dbus::MessageReader reader(response);
+ power_manager::RegisterSuspendDelayReply protobuf;
+ if (!reader.PopArrayOfBytesAsProto(&protobuf)) {
+ LOG(ERROR) << "Unable to parse reply from "
+ << power_manager::kRegisterSuspendDelayMethod;
+ return;
+ }
+ suspend_delay_id_ = protobuf.delay_id();
+ has_suspend_delay_id_ = true;
+ }
+
void IdleNotifySignalReceived(dbus::Signal* signal) {
dbus::MessageReader reader(signal);
int64 threshold = 0;
@@ -481,6 +550,44 @@ class PowerManagerClientImpl : public PowerManagerClient {
FOR_EACH_OBSERVER(Observer, observers_, ScreenDimmingRequested(state));
}
+ void SuspendImminentReceived(dbus::Signal* signal) {
+ if (!has_suspend_delay_id_) {
+ LOG(ERROR) << "Received unrequested "
+ << power_manager::kSuspendImminentSignal << " signal";
+ return;
+ }
+
+ dbus::MessageReader reader(signal);
+ power_manager::SuspendImminent protobuf_imminent;
+ if (!reader.PopArrayOfBytesAsProto(&protobuf_imminent)) {
+ LOG(ERROR) << "Unable to decode protocol buffer from "
+ << power_manager::kSuspendImminentSignal << " signal";
+ return;
+ }
+ int32 suspend_id = protobuf_imminent.suspend_id();
+
+ FOR_EACH_OBSERVER(Observer, observers_, SuspendImminent());
+
+ dbus::MethodCall method_call(
+ power_manager::kPowerManagerInterface,
+ power_manager::kHandleSuspendReadinessMethod);
+ dbus::MessageWriter writer(&method_call);
+
+ power_manager::SuspendReadinessInfo protobuf_request;
+ protobuf_request.set_delay_id(suspend_delay_id_);
+ protobuf_request.set_suspend_id(suspend_id);
+
+ if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) {
+ LOG(ERROR) << "Error constructing message for "
+ << power_manager::kHandleSuspendReadinessMethod;
+ return;
+ }
+ power_manager_proxy_->CallMethod(
+ &method_call,
+ dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ dbus::ObjectProxy::EmptyResponseCallback());
+ }
+
void InputEventReceived(dbus::Signal* signal) {
dbus::MessageReader reader(signal);
power_manager::InputEvent proto;
@@ -542,6 +649,10 @@ class PowerManagerClientImpl : public PowerManagerClient {
dbus::ObjectProxy* power_manager_proxy_;
ObserverList<Observer> observers_;
+ // The delay_id_ obtained from the RegisterSuspendDelay request.
+ int32 suspend_delay_id_;
+ bool has_suspend_delay_id_;
+
// Wall time from the latest signal telling us that the system was about to
// suspend to memory.
base::Time last_suspend_wall_time_;
diff --git a/chromeos/dbus/power_manager_client.h b/chromeos/dbus/power_manager_client.h
index e091d90..1e23b7e 100644
--- a/chromeos/dbus/power_manager_client.h
+++ b/chromeos/dbus/power_manager_client.h
@@ -67,6 +67,10 @@ class CHROMEOS_EXPORT PowerManagerClient {
// (as opposed to the more-common method of adjusting the backlight).
virtual void ScreenDimmingRequested(ScreenDimmingState state) {}
+ // Called when the system is about to suspend. Suspend is deferred until
+ // all observers' implementations of this method have finished running.
+ virtual void SuspendImminent() {}
+
// Called when the power button is pressed or released.
virtual void PowerButtonEventReceived(bool down,
const base::TimeTicks& timestamp) {}
diff --git a/chromeos/display/output_configurator.cc b/chromeos/display/output_configurator.cc
index b6480de..b689406 100644
--- a/chromeos/display/output_configurator.cc
+++ b/chromeos/display/output_configurator.cc
@@ -769,9 +769,9 @@ bool OutputConfigurator::Dispatch(const base::NativeEvent& event) {
}
// Sets the timer for NotifyOnDisplayChanged(). When an output state change
- // is issued, several notifications chould arrive and NotifyOnDisplayChanged()
+ // is issued, several notifications should arrive and NotifyOnDisplayChanged()
// should be called once for the last one. The timer could lead at most a few
- // handreds milliseconds of delay for the notification, but it would be
+ // hundreds of milliseconds of delay for the notification, but it would be
// unrecognizable for users.
if (notification_timer_.get()) {
notification_timer_->Reset();
@@ -799,6 +799,17 @@ bool OutputConfigurator::IsInternalOutputName(const std::string& name) {
return name.find(kInternal_LVDS) == 0 || name.find(kInternal_eDP) == 0;
}
+void OutputConfigurator::SuspendDisplays() {
+ // Turn displays on before suspend. At this point, the backlight is off,
+ // so we turn on the internal display so that we can resume directly into
+ // "on" state. This greatly reduces resume times.
+ ScreenPowerSet(true, true);
+ // We need to make sure that the monitor configuration we just did actually
+ // completes before we return, because otherwise the X message could be
+ // racing with the HandleSuspendReadiness message.
+ XSync(base::MessagePumpAuraX11::GetDefaultXDisplay(), 0);
+}
+
void OutputConfigurator::NotifyOnDisplayChanged() {
notification_timer_.reset();
FOR_EACH_OBSERVER(Observer, observers_, OnDisplayModeChanged());
diff --git a/chromeos/display/output_configurator.h b/chromeos/display/output_configurator.h
index abb89c3..418668e 100644
--- a/chromeos/display/output_configurator.h
+++ b/chromeos/display/output_configurator.h
@@ -101,6 +101,11 @@ class CHROMEOS_EXPORT OutputConfigurator : public MessageLoop::Dispatcher {
// Tells if the output specified by |name| is for internal display.
static bool IsInternalOutputName(const std::string& name);
+ // Set all the displays into pre-suspend mode; usually this means configure
+ // them for their resume state. This allows faster resume on machines where
+ // display configuration is slow.
+ void SuspendDisplays();
+
private:
// Fires OnDisplayModeChanged() event to the observers.
void NotifyOnDisplayChanged();