power_manager_client.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chromeos/dbus/power_manager_client.h" 6 7#include <algorithm> 8 9#include "base/bind.h" 10#include "base/callback.h" 11#include "base/format_macros.h" 12#include "base/logging.h" 13#include "base/memory/scoped_ptr.h" 14#include "base/message_loop.h" 15#include "base/observer_list.h" 16#include "base/strings/stringprintf.h" 17#include "base/threading/platform_thread.h" 18#include "base/time/time.h" 19#include "base/timer/timer.h" 20#include "chromeos/dbus/power_manager/input_event.pb.h" 21#include "chromeos/dbus/power_manager/peripheral_battery_status.pb.h" 22#include "chromeos/dbus/power_manager/policy.pb.h" 23#include "chromeos/dbus/power_manager/power_supply_properties.pb.h" 24#include "chromeos/dbus/power_manager/suspend.pb.h" 25#include "dbus/bus.h" 26#include "dbus/message.h" 27#include "dbus/object_path.h" 28#include "dbus/object_proxy.h" 29#include "third_party/cros_system_api/dbus/service_constants.h" 30 31namespace chromeos { 32 33// Maximum amount of time that the power manager will wait for Chrome to 34// say that it's ready for the system to be suspended, in milliseconds. 35const int kSuspendDelayTimeoutMs = 5000; 36 37// Human-readable description of Chrome's suspend delay. 38const char kSuspendDelayDescription[] = "chrome"; 39 40// The PowerManagerClient implementation used in production. 41class PowerManagerClientImpl : public PowerManagerClient { 42 public: 43 explicit PowerManagerClientImpl(dbus::Bus* bus) 44 : origin_thread_id_(base::PlatformThread::CurrentId()), 45 power_manager_proxy_(NULL), 46 suspend_delay_id_(-1), 47 has_suspend_delay_id_(false), 48 pending_suspend_id_(-1), 49 suspend_is_pending_(false), 50 num_pending_suspend_readiness_callbacks_(0), 51 last_is_projecting_(false), 52 weak_ptr_factory_(this) { 53 power_manager_proxy_ = bus->GetObjectProxy( 54 power_manager::kPowerManagerServiceName, 55 dbus::ObjectPath(power_manager::kPowerManagerServicePath)); 56 57 power_manager_proxy_->SetNameOwnerChangedCallback( 58 base::Bind(&PowerManagerClientImpl::NameOwnerChangedReceived, 59 weak_ptr_factory_.GetWeakPtr())); 60 61 // Monitor the D-Bus signal for brightness changes. Only the power 62 // manager knows the actual brightness level. We don't cache the 63 // brightness level in Chrome as it'll make things less reliable. 64 power_manager_proxy_->ConnectToSignal( 65 power_manager::kPowerManagerInterface, 66 power_manager::kBrightnessChangedSignal, 67 base::Bind(&PowerManagerClientImpl::BrightnessChangedReceived, 68 weak_ptr_factory_.GetWeakPtr()), 69 base::Bind(&PowerManagerClientImpl::SignalConnected, 70 weak_ptr_factory_.GetWeakPtr())); 71 72 power_manager_proxy_->ConnectToSignal( 73 power_manager::kPowerManagerInterface, 74 power_manager::kPeripheralBatteryStatusSignal, 75 base::Bind(&PowerManagerClientImpl::PeripheralBatteryStatusReceived, 76 weak_ptr_factory_.GetWeakPtr()), 77 base::Bind(&PowerManagerClientImpl::SignalConnected, 78 weak_ptr_factory_.GetWeakPtr())); 79 80 power_manager_proxy_->ConnectToSignal( 81 power_manager::kPowerManagerInterface, 82 power_manager::kPowerSupplyPollSignal, 83 base::Bind(&PowerManagerClientImpl::PowerSupplyPollReceived, 84 weak_ptr_factory_.GetWeakPtr()), 85 base::Bind(&PowerManagerClientImpl::SignalConnected, 86 weak_ptr_factory_.GetWeakPtr())); 87 88 power_manager_proxy_->ConnectToSignal( 89 power_manager::kPowerManagerInterface, 90 power_manager::kIdleNotifySignal, 91 base::Bind(&PowerManagerClientImpl::IdleNotifySignalReceived, 92 weak_ptr_factory_.GetWeakPtr()), 93 base::Bind(&PowerManagerClientImpl::SignalConnected, 94 weak_ptr_factory_.GetWeakPtr())); 95 96 power_manager_proxy_->ConnectToSignal( 97 power_manager::kPowerManagerInterface, 98 power_manager::kInputEventSignal, 99 base::Bind(&PowerManagerClientImpl::InputEventReceived, 100 weak_ptr_factory_.GetWeakPtr()), 101 base::Bind(&PowerManagerClientImpl::SignalConnected, 102 weak_ptr_factory_.GetWeakPtr())); 103 104 power_manager_proxy_->ConnectToSignal( 105 power_manager::kPowerManagerInterface, 106 power_manager::kSuspendStateChangedSignal, 107 base::Bind(&PowerManagerClientImpl::SuspendStateChangedReceived, 108 weak_ptr_factory_.GetWeakPtr()), 109 base::Bind(&PowerManagerClientImpl::SignalConnected, 110 weak_ptr_factory_.GetWeakPtr())); 111 112 power_manager_proxy_->ConnectToSignal( 113 power_manager::kPowerManagerInterface, 114 power_manager::kSuspendImminentSignal, 115 base::Bind( 116 &PowerManagerClientImpl::SuspendImminentReceived, 117 weak_ptr_factory_.GetWeakPtr()), 118 base::Bind(&PowerManagerClientImpl::SignalConnected, 119 weak_ptr_factory_.GetWeakPtr())); 120 121 power_manager_proxy_->ConnectToSignal( 122 power_manager::kPowerManagerInterface, 123 power_manager::kIdleActionImminentSignal, 124 base::Bind( 125 &PowerManagerClientImpl::IdleActionImminentReceived, 126 weak_ptr_factory_.GetWeakPtr()), 127 base::Bind(&PowerManagerClientImpl::SignalConnected, 128 weak_ptr_factory_.GetWeakPtr())); 129 130 power_manager_proxy_->ConnectToSignal( 131 power_manager::kPowerManagerInterface, 132 power_manager::kIdleActionDeferredSignal, 133 base::Bind( 134 &PowerManagerClientImpl::IdleActionDeferredReceived, 135 weak_ptr_factory_.GetWeakPtr()), 136 base::Bind(&PowerManagerClientImpl::SignalConnected, 137 weak_ptr_factory_.GetWeakPtr())); 138 139 RegisterSuspendDelay(); 140 } 141 142 virtual ~PowerManagerClientImpl() { 143 // Here we should unregister suspend notifications from powerd, 144 // however: 145 // - The lifetime of the PowerManagerClientImpl can extend past that of 146 // the objectproxy, 147 // - power_manager can already detect that the client is gone and 148 // unregister our suspend delay. 149 } 150 151 // PowerManagerClient overrides: 152 153 virtual void AddObserver(Observer* observer) OVERRIDE { 154 CHECK(observer); // http://crbug.com/119976 155 observers_.AddObserver(observer); 156 } 157 158 virtual void RemoveObserver(Observer* observer) OVERRIDE { 159 observers_.RemoveObserver(observer); 160 } 161 162 virtual bool HasObserver(Observer* observer) OVERRIDE { 163 return observers_.HasObserver(observer); 164 } 165 166 virtual void DecreaseScreenBrightness(bool allow_off) OVERRIDE { 167 dbus::MethodCall method_call( 168 power_manager::kPowerManagerInterface, 169 power_manager::kDecreaseScreenBrightness); 170 dbus::MessageWriter writer(&method_call); 171 writer.AppendBool(allow_off); 172 power_manager_proxy_->CallMethod( 173 &method_call, 174 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 175 dbus::ObjectProxy::EmptyResponseCallback()); 176 } 177 178 virtual void IncreaseScreenBrightness() OVERRIDE { 179 SimpleMethodCallToPowerManager(power_manager::kIncreaseScreenBrightness); 180 } 181 182 virtual void DecreaseKeyboardBrightness() OVERRIDE { 183 SimpleMethodCallToPowerManager(power_manager::kDecreaseKeyboardBrightness); 184 } 185 186 virtual void IncreaseKeyboardBrightness() OVERRIDE { 187 SimpleMethodCallToPowerManager(power_manager::kIncreaseKeyboardBrightness); 188 } 189 190 virtual void SetScreenBrightnessPercent(double percent, 191 bool gradual) OVERRIDE { 192 dbus::MethodCall method_call( 193 power_manager::kPowerManagerInterface, 194 power_manager::kSetScreenBrightnessPercent); 195 dbus::MessageWriter writer(&method_call); 196 writer.AppendDouble(percent); 197 writer.AppendInt32( 198 gradual ? 199 power_manager::kBrightnessTransitionGradual : 200 power_manager::kBrightnessTransitionInstant); 201 power_manager_proxy_->CallMethod( 202 &method_call, 203 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 204 dbus::ObjectProxy::EmptyResponseCallback()); 205 } 206 207 virtual void GetScreenBrightnessPercent( 208 const GetScreenBrightnessPercentCallback& callback) OVERRIDE { 209 dbus::MethodCall method_call(power_manager::kPowerManagerInterface, 210 power_manager::kGetScreenBrightnessPercent); 211 power_manager_proxy_->CallMethod( 212 &method_call, 213 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 214 base::Bind(&PowerManagerClientImpl::OnGetScreenBrightnessPercent, 215 weak_ptr_factory_.GetWeakPtr(), callback)); 216 } 217 218 virtual void RequestStatusUpdate() OVERRIDE { 219 dbus::MethodCall method_call( 220 power_manager::kPowerManagerInterface, 221 power_manager::kGetPowerSupplyPropertiesMethod); 222 power_manager_proxy_->CallMethod( 223 &method_call, 224 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 225 base::Bind(&PowerManagerClientImpl::OnGetPowerSupplyPropertiesMethod, 226 weak_ptr_factory_.GetWeakPtr())); 227 } 228 229 virtual void RequestRestart() OVERRIDE { 230 SimpleMethodCallToPowerManager(power_manager::kRequestRestartMethod); 231 }; 232 233 virtual void RequestShutdown() OVERRIDE { 234 SimpleMethodCallToPowerManager(power_manager::kRequestShutdownMethod); 235 } 236 237 virtual void RequestIdleNotification(int64 threshold) OVERRIDE { 238 dbus::MethodCall method_call(power_manager::kPowerManagerInterface, 239 power_manager::kRequestIdleNotification); 240 dbus::MessageWriter writer(&method_call); 241 writer.AppendInt64(threshold); 242 243 power_manager_proxy_->CallMethod( 244 &method_call, 245 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 246 dbus::ObjectProxy::EmptyResponseCallback()); 247 } 248 249 virtual void NotifyUserActivity() OVERRIDE { 250 SimpleMethodCallToPowerManager(power_manager::kHandleUserActivityMethod); 251 } 252 253 virtual void NotifyVideoActivity(bool is_fullscreen) OVERRIDE { 254 dbus::MethodCall method_call( 255 power_manager::kPowerManagerInterface, 256 power_manager::kHandleVideoActivityMethod); 257 dbus::MessageWriter writer(&method_call); 258 writer.AppendBool(is_fullscreen); 259 260 power_manager_proxy_->CallMethod( 261 &method_call, 262 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 263 dbus::ObjectProxy::EmptyResponseCallback()); 264 } 265 266 virtual void SetPolicy( 267 const power_manager::PowerManagementPolicy& policy) OVERRIDE { 268 dbus::MethodCall method_call( 269 power_manager::kPowerManagerInterface, 270 power_manager::kSetPolicyMethod); 271 dbus::MessageWriter writer(&method_call); 272 if (!writer.AppendProtoAsArrayOfBytes(policy)) { 273 LOG(ERROR) << "Error calling " << power_manager::kSetPolicyMethod; 274 return; 275 } 276 power_manager_proxy_->CallMethod( 277 &method_call, 278 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 279 dbus::ObjectProxy::EmptyResponseCallback()); 280 } 281 282 virtual void SetIsProjecting(bool is_projecting) OVERRIDE { 283 dbus::MethodCall method_call( 284 power_manager::kPowerManagerInterface, 285 power_manager::kSetIsProjectingMethod); 286 dbus::MessageWriter writer(&method_call); 287 writer.AppendBool(is_projecting); 288 power_manager_proxy_->CallMethod( 289 &method_call, 290 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 291 dbus::ObjectProxy::EmptyResponseCallback()); 292 last_is_projecting_ = is_projecting; 293 } 294 295 virtual base::Closure GetSuspendReadinessCallback() OVERRIDE { 296 DCHECK(OnOriginThread()); 297 DCHECK(suspend_is_pending_); 298 num_pending_suspend_readiness_callbacks_++; 299 return base::Bind(&PowerManagerClientImpl::HandleObserverSuspendReadiness, 300 weak_ptr_factory_.GetWeakPtr(), pending_suspend_id_); 301 } 302 303 private: 304 // Returns true if the current thread is the origin thread. 305 bool OnOriginThread() { 306 return base::PlatformThread::CurrentId() == origin_thread_id_; 307 } 308 309 // Called when a dbus signal is initially connected. 310 void SignalConnected(const std::string& interface_name, 311 const std::string& signal_name, 312 bool success) { 313 LOG_IF(WARNING, !success) << "Failed to connect to signal " 314 << signal_name << "."; 315 } 316 317 // Make a method call to power manager with no arguments and no response. 318 void SimpleMethodCallToPowerManager(const std::string& method_name) { 319 dbus::MethodCall method_call(power_manager::kPowerManagerInterface, 320 method_name); 321 power_manager_proxy_->CallMethod( 322 &method_call, 323 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 324 dbus::ObjectProxy::EmptyResponseCallback()); 325 } 326 327 void NameOwnerChangedReceived(dbus::Signal* signal) { 328 VLOG(1) << "Power manager restarted"; 329 RegisterSuspendDelay(); 330 SetIsProjecting(last_is_projecting_); 331 FOR_EACH_OBSERVER(Observer, observers_, PowerManagerRestarted()); 332 } 333 334 void BrightnessChangedReceived(dbus::Signal* signal) { 335 dbus::MessageReader reader(signal); 336 int32 brightness_level = 0; 337 bool user_initiated = 0; 338 if (!(reader.PopInt32(&brightness_level) && 339 reader.PopBool(&user_initiated))) { 340 LOG(ERROR) << "Brightness changed signal had incorrect parameters: " 341 << signal->ToString(); 342 return; 343 } 344 VLOG(1) << "Brightness changed to " << brightness_level 345 << ": user initiated " << user_initiated; 346 FOR_EACH_OBSERVER(Observer, observers_, 347 BrightnessChanged(brightness_level, user_initiated)); 348 } 349 350 void PeripheralBatteryStatusReceived(dbus::Signal* signal) { 351 dbus::MessageReader reader(signal); 352 power_manager::PeripheralBatteryStatus protobuf_status; 353 if (!reader.PopArrayOfBytesAsProto(&protobuf_status)) { 354 LOG(ERROR) << "Unable to decode protocol buffer from " 355 << power_manager::kPeripheralBatteryStatusSignal << " signal"; 356 return; 357 } 358 359 std::string path = protobuf_status.path(); 360 std::string name = protobuf_status.name(); 361 int level = protobuf_status.has_level() ? protobuf_status.level() : -1; 362 363 VLOG(1) << "Device battery status received " << level 364 << " for " << name << " at " << path; 365 366 FOR_EACH_OBSERVER(Observer, observers_, 367 PeripheralBatteryStatusReceived(path, name, level)); 368 } 369 370 void PowerSupplyPollReceived(dbus::Signal* signal) { 371 VLOG(1) << "Received power supply poll signal."; 372 dbus::MessageReader reader(signal); 373 power_manager::PowerSupplyProperties protobuf; 374 if (reader.PopArrayOfBytesAsProto(&protobuf)) { 375 FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(protobuf)); 376 } else { 377 LOG(ERROR) << "Unable to decode " 378 << power_manager::kPowerSupplyPollSignal << "signal"; 379 } 380 } 381 382 void OnGetPowerSupplyPropertiesMethod(dbus::Response* response) { 383 if (!response) { 384 LOG(ERROR) << "Error calling " 385 << power_manager::kGetPowerSupplyPropertiesMethod; 386 return; 387 } 388 389 dbus::MessageReader reader(response); 390 power_manager::PowerSupplyProperties protobuf; 391 if (reader.PopArrayOfBytesAsProto(&protobuf)) { 392 FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(protobuf)); 393 } else { 394 LOG(ERROR) << "Unable to decode " 395 << power_manager::kGetPowerSupplyPropertiesMethod 396 << " response"; 397 } 398 } 399 400 void OnGetScreenBrightnessPercent( 401 const GetScreenBrightnessPercentCallback& callback, 402 dbus::Response* response) { 403 if (!response) { 404 LOG(ERROR) << "Error calling " 405 << power_manager::kGetScreenBrightnessPercent; 406 return; 407 } 408 dbus::MessageReader reader(response); 409 double percent = 0.0; 410 if (!reader.PopDouble(&percent)) 411 LOG(ERROR) << "Error reading response from powerd: " 412 << response->ToString(); 413 callback.Run(percent); 414 } 415 416 void OnRegisterSuspendDelayReply(dbus::Response* response) { 417 if (!response) { 418 LOG(ERROR) << "Error calling " 419 << power_manager::kRegisterSuspendDelayMethod; 420 return; 421 } 422 423 dbus::MessageReader reader(response); 424 power_manager::RegisterSuspendDelayReply protobuf; 425 if (!reader.PopArrayOfBytesAsProto(&protobuf)) { 426 LOG(ERROR) << "Unable to parse reply from " 427 << power_manager::kRegisterSuspendDelayMethod; 428 return; 429 } 430 431 suspend_delay_id_ = protobuf.delay_id(); 432 has_suspend_delay_id_ = true; 433 VLOG(1) << "Registered suspend delay " << suspend_delay_id_; 434 } 435 436 void IdleNotifySignalReceived(dbus::Signal* signal) { 437 dbus::MessageReader reader(signal); 438 int64 threshold = 0; 439 if (!reader.PopInt64(&threshold)) { 440 LOG(ERROR) << "Idle Notify signal had incorrect parameters: " 441 << signal->ToString(); 442 return; 443 } 444 DCHECK_GT(threshold, 0); 445 446 VLOG(1) << "Idle Notify: " << threshold; 447 FOR_EACH_OBSERVER(Observer, observers_, IdleNotify(threshold)); 448 } 449 450 void SuspendImminentReceived(dbus::Signal* signal) { 451 if (!has_suspend_delay_id_) { 452 LOG(ERROR) << "Received unrequested " 453 << power_manager::kSuspendImminentSignal << " signal"; 454 return; 455 } 456 457 dbus::MessageReader reader(signal); 458 power_manager::SuspendImminent protobuf_imminent; 459 if (!reader.PopArrayOfBytesAsProto(&protobuf_imminent)) { 460 LOG(ERROR) << "Unable to decode protocol buffer from " 461 << power_manager::kSuspendImminentSignal << " signal"; 462 return; 463 } 464 465 if (suspend_is_pending_) { 466 LOG(WARNING) << "Got " << power_manager::kSuspendImminentSignal 467 << " signal about pending suspend attempt " 468 << protobuf_imminent.suspend_id() << " while still waiting " 469 << "on attempt " << pending_suspend_id_; 470 } 471 472 pending_suspend_id_ = protobuf_imminent.suspend_id(); 473 suspend_is_pending_ = true; 474 num_pending_suspend_readiness_callbacks_ = 0; 475 FOR_EACH_OBSERVER(Observer, observers_, SuspendImminent()); 476 MaybeReportSuspendReadiness(); 477 } 478 479 void IdleActionImminentReceived(dbus::Signal* signal) { 480 FOR_EACH_OBSERVER(Observer, observers_, IdleActionImminent()); 481 } 482 483 void IdleActionDeferredReceived(dbus::Signal* signal) { 484 FOR_EACH_OBSERVER(Observer, observers_, IdleActionDeferred()); 485 } 486 487 void InputEventReceived(dbus::Signal* signal) { 488 dbus::MessageReader reader(signal); 489 power_manager::InputEvent proto; 490 if (!reader.PopArrayOfBytesAsProto(&proto)) { 491 LOG(ERROR) << "Unable to decode protocol buffer from " 492 << power_manager::kInputEventSignal << " signal"; 493 return; 494 } 495 496 base::TimeTicks timestamp = 497 base::TimeTicks::FromInternalValue(proto.timestamp()); 498 VLOG(1) << "Got " << power_manager::kInputEventSignal << " signal:" 499 << " type=" << proto.type() << " timestamp=" << proto.timestamp(); 500 switch (proto.type()) { 501 case power_manager::InputEvent_Type_POWER_BUTTON_DOWN: 502 case power_manager::InputEvent_Type_POWER_BUTTON_UP: { 503 bool down = 504 (proto.type() == power_manager::InputEvent_Type_POWER_BUTTON_DOWN); 505 FOR_EACH_OBSERVER(PowerManagerClient::Observer, observers_, 506 PowerButtonEventReceived(down, timestamp)); 507 break; 508 } 509 case power_manager::InputEvent_Type_LID_OPEN: 510 case power_manager::InputEvent_Type_LID_CLOSED: { 511 bool open = 512 (proto.type() == power_manager::InputEvent_Type_LID_OPEN); 513 FOR_EACH_OBSERVER(PowerManagerClient::Observer, observers_, 514 LidEventReceived(open, timestamp)); 515 break; 516 } 517 } 518 } 519 520 void SuspendStateChangedReceived(dbus::Signal* signal) { 521 dbus::MessageReader reader(signal); 522 power_manager::SuspendState proto; 523 if (!reader.PopArrayOfBytesAsProto(&proto)) { 524 LOG(ERROR) << "Unable to decode protocol buffer from " 525 << power_manager::kSuspendStateChangedSignal << " signal"; 526 return; 527 } 528 529 VLOG(1) << "Got " << power_manager::kSuspendStateChangedSignal << " signal:" 530 << " type=" << proto.type() << " wall_time=" << proto.wall_time(); 531 base::Time wall_time = 532 base::Time::FromInternalValue(proto.wall_time()); 533 switch (proto.type()) { 534 case power_manager::SuspendState_Type_SUSPEND_TO_MEMORY: 535 last_suspend_wall_time_ = wall_time; 536 break; 537 case power_manager::SuspendState_Type_RESUME: 538 FOR_EACH_OBSERVER( 539 PowerManagerClient::Observer, observers_, 540 SystemResumed(wall_time - last_suspend_wall_time_)); 541 break; 542 } 543 } 544 545 // Registers a suspend delay with the power manager. This is usually 546 // only called at startup, but if the power manager restarts, we need to 547 // create a new delay. 548 void RegisterSuspendDelay() { 549 // Throw out any old delay that was registered. 550 suspend_delay_id_ = -1; 551 has_suspend_delay_id_ = false; 552 553 dbus::MethodCall method_call( 554 power_manager::kPowerManagerInterface, 555 power_manager::kRegisterSuspendDelayMethod); 556 dbus::MessageWriter writer(&method_call); 557 558 power_manager::RegisterSuspendDelayRequest protobuf_request; 559 base::TimeDelta timeout = 560 base::TimeDelta::FromMilliseconds(kSuspendDelayTimeoutMs); 561 protobuf_request.set_timeout(timeout.ToInternalValue()); 562 protobuf_request.set_description(kSuspendDelayDescription); 563 564 if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) { 565 LOG(ERROR) << "Error constructing message for " 566 << power_manager::kRegisterSuspendDelayMethod; 567 return; 568 } 569 power_manager_proxy_->CallMethod( 570 &method_call, 571 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 572 base::Bind( 573 &PowerManagerClientImpl::OnRegisterSuspendDelayReply, 574 weak_ptr_factory_.GetWeakPtr())); 575 } 576 577 // Records the fact that an observer has finished doing asynchronous work 578 // that was blocking a pending suspend attempt and possibly reports 579 // suspend readiness to powerd. Called by callbacks returned via 580 // GetSuspendReadinessCallback(). 581 void HandleObserverSuspendReadiness(int32 suspend_id) { 582 DCHECK(OnOriginThread()); 583 if (!suspend_is_pending_ || suspend_id != pending_suspend_id_) 584 return; 585 586 num_pending_suspend_readiness_callbacks_--; 587 MaybeReportSuspendReadiness(); 588 } 589 590 // Reports suspend readiness to powerd if no observers are still holding 591 // suspend readiness callbacks. 592 void MaybeReportSuspendReadiness() { 593 if (!suspend_is_pending_ || num_pending_suspend_readiness_callbacks_ > 0) 594 return; 595 596 dbus::MethodCall method_call( 597 power_manager::kPowerManagerInterface, 598 power_manager::kHandleSuspendReadinessMethod); 599 dbus::MessageWriter writer(&method_call); 600 601 power_manager::SuspendReadinessInfo protobuf_request; 602 protobuf_request.set_delay_id(suspend_delay_id_); 603 protobuf_request.set_suspend_id(pending_suspend_id_); 604 605 pending_suspend_id_ = -1; 606 suspend_is_pending_ = false; 607 608 if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) { 609 LOG(ERROR) << "Error constructing message for " 610 << power_manager::kHandleSuspendReadinessMethod; 611 return; 612 } 613 power_manager_proxy_->CallMethod( 614 &method_call, 615 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 616 dbus::ObjectProxy::EmptyResponseCallback()); 617 } 618 619 // Origin thread (i.e. the UI thread in production). 620 base::PlatformThreadId origin_thread_id_; 621 622 dbus::ObjectProxy* power_manager_proxy_; 623 ObserverList<Observer> observers_; 624 625 // The delay_id_ obtained from the RegisterSuspendDelay request. 626 int32 suspend_delay_id_; 627 bool has_suspend_delay_id_; 628 629 // powerd-supplied ID corresponding to an imminent suspend attempt that is 630 // currently being delayed. 631 int32 pending_suspend_id_; 632 bool suspend_is_pending_; 633 634 // Number of callbacks that have been returned by 635 // GetSuspendReadinessCallback() during the currently-pending suspend 636 // attempt but have not yet been called. 637 int num_pending_suspend_readiness_callbacks_; 638 639 // Wall time from the latest signal telling us that the system was about to 640 // suspend to memory. 641 base::Time last_suspend_wall_time_; 642 643 // Last state passed to SetIsProjecting(). 644 bool last_is_projecting_; 645 646 // Note: This should remain the last member so it'll be destroyed and 647 // invalidate its weak pointers before any other members are destroyed. 648 base::WeakPtrFactory<PowerManagerClientImpl> weak_ptr_factory_; 649 650 DISALLOW_COPY_AND_ASSIGN(PowerManagerClientImpl); 651}; 652 653// The PowerManagerClient implementation used on Linux desktop, 654// which does nothing. 655class PowerManagerClientStubImpl : public PowerManagerClient { 656 public: 657 PowerManagerClientStubImpl() 658 : discharging_(true), 659 battery_percentage_(40), 660 brightness_(50.0), 661 pause_count_(2), 662 cycle_count_(0), 663 weak_ptr_factory_(this) { 664 const int kStatusUpdateMs = 1000; 665 update_timer_.Start(FROM_HERE, 666 base::TimeDelta::FromMilliseconds(kStatusUpdateMs), this, 667 &PowerManagerClientStubImpl::UpdateStatus); 668 } 669 670 virtual ~PowerManagerClientStubImpl() {} 671 672 // PowerManagerClient overrides: 673 674 virtual void AddObserver(Observer* observer) OVERRIDE { 675 observers_.AddObserver(observer); 676 } 677 678 virtual void RemoveObserver(Observer* observer) OVERRIDE { 679 observers_.RemoveObserver(observer); 680 } 681 682 virtual bool HasObserver(Observer* observer) OVERRIDE { 683 return observers_.HasObserver(observer); 684 } 685 686 virtual void DecreaseScreenBrightness(bool allow_off) OVERRIDE { 687 VLOG(1) << "Requested to descrease screen brightness"; 688 SetBrightness(brightness_ - 5.0, true); 689 } 690 691 virtual void IncreaseScreenBrightness() OVERRIDE { 692 VLOG(1) << "Requested to increase screen brightness"; 693 SetBrightness(brightness_ + 5.0, true); 694 } 695 696 virtual void SetScreenBrightnessPercent(double percent, 697 bool gradual) OVERRIDE { 698 VLOG(1) << "Requested to set screen brightness to " << percent << "% " 699 << (gradual ? "gradually" : "instantaneously"); 700 SetBrightness(percent, false); 701 } 702 703 virtual void GetScreenBrightnessPercent( 704 const GetScreenBrightnessPercentCallback& callback) OVERRIDE { 705 callback.Run(brightness_); 706 } 707 708 virtual void DecreaseKeyboardBrightness() OVERRIDE { 709 VLOG(1) << "Requested to descrease keyboard brightness"; 710 } 711 712 virtual void IncreaseKeyboardBrightness() OVERRIDE { 713 VLOG(1) << "Requested to increase keyboard brightness"; 714 } 715 716 virtual void RequestStatusUpdate() OVERRIDE { 717 base::MessageLoop::current()->PostTask(FROM_HERE, 718 base::Bind(&PowerManagerClientStubImpl::UpdateStatus, 719 weak_ptr_factory_.GetWeakPtr())); 720 } 721 722 virtual void RequestRestart() OVERRIDE {} 723 virtual void RequestShutdown() OVERRIDE {} 724 725 virtual void RequestIdleNotification(int64 threshold) OVERRIDE { 726 base::MessageLoop::current()->PostDelayedTask( 727 FROM_HERE, 728 base::Bind(&PowerManagerClientStubImpl::TriggerIdleNotify, 729 weak_ptr_factory_.GetWeakPtr(), threshold), 730 base::TimeDelta::FromMilliseconds(threshold)); 731 } 732 733 virtual void NotifyUserActivity() OVERRIDE {} 734 virtual void NotifyVideoActivity(bool is_fullscreen) OVERRIDE {} 735 virtual void SetPolicy( 736 const power_manager::PowerManagementPolicy& policy) OVERRIDE {} 737 virtual void SetIsProjecting(bool is_projecting) OVERRIDE {} 738 virtual base::Closure GetSuspendReadinessCallback() OVERRIDE { 739 return base::Closure(); 740 } 741 742 private: 743 void UpdateStatus() { 744 if (pause_count_ > 0) { 745 pause_count_--; 746 if (pause_count_ == 2) 747 discharging_ = !discharging_; 748 } else { 749 if (discharging_) 750 battery_percentage_ -= (battery_percentage_ <= 10 ? 1 : 10); 751 else 752 battery_percentage_ += (battery_percentage_ >= 10 ? 10 : 1); 753 battery_percentage_ = std::min(std::max(battery_percentage_, 0), 100); 754 // We pause at 0 and 100% so that it's easier to check those conditions. 755 if (battery_percentage_ == 0 || battery_percentage_ == 100) { 756 pause_count_ = 4; 757 if (battery_percentage_ == 100) 758 cycle_count_ = (cycle_count_ + 1) % 3; 759 } 760 } 761 762 const int kSecondsToEmptyFullBattery = 3 * 60 * 60; // 3 hours. 763 int64 remaining_battery_time = 764 std::max(1, battery_percentage_ * kSecondsToEmptyFullBattery / 100); 765 766 props_.Clear(); 767 768 switch (cycle_count_) { 769 case 0: 770 // Say that the system is charging with AC connected and 771 // discharging without any charger connected. 772 props_.set_external_power(discharging_ ? 773 power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED : 774 power_manager::PowerSupplyProperties_ExternalPower_AC); 775 break; 776 case 1: 777 // Say that the system is both charging and discharging on USB 778 // (i.e. a low-power charger). 779 props_.set_external_power( 780 power_manager::PowerSupplyProperties_ExternalPower_USB); 781 break; 782 case 2: 783 // Say that the system is both charging and discharging on AC. 784 props_.set_external_power( 785 power_manager::PowerSupplyProperties_ExternalPower_AC); 786 break; 787 default: 788 NOTREACHED() << "Unhandled cycle " << cycle_count_; 789 } 790 791 if (battery_percentage_ == 100 && !discharging_) { 792 props_.set_battery_state( 793 power_manager::PowerSupplyProperties_BatteryState_FULL); 794 } else if (!discharging_) { 795 props_.set_battery_state( 796 power_manager::PowerSupplyProperties_BatteryState_CHARGING); 797 props_.set_battery_time_to_full_sec(std::max(static_cast<int64>(1), 798 kSecondsToEmptyFullBattery - remaining_battery_time)); 799 } else { 800 props_.set_battery_state( 801 power_manager::PowerSupplyProperties_BatteryState_DISCHARGING); 802 props_.set_battery_time_to_empty_sec(remaining_battery_time); 803 } 804 805 props_.set_battery_percent(battery_percentage_); 806 props_.set_is_calculating_battery_time(pause_count_ > 1); 807 808 FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(props_)); 809 } 810 811 void SetBrightness(double percent, bool user_initiated) { 812 brightness_ = std::min(std::max(0.0, percent), 100.0); 813 int brightness_level = static_cast<int>(brightness_); 814 FOR_EACH_OBSERVER(Observer, observers_, 815 BrightnessChanged(brightness_level, user_initiated)); 816 } 817 818 void TriggerIdleNotify(int64 threshold) { 819 FOR_EACH_OBSERVER(Observer, observers_, IdleNotify(threshold)); 820 } 821 822 bool discharging_; 823 int battery_percentage_; 824 double brightness_; 825 int pause_count_; 826 int cycle_count_; 827 ObserverList<Observer> observers_; 828 base::RepeatingTimer<PowerManagerClientStubImpl> update_timer_; 829 power_manager::PowerSupplyProperties props_; 830 831 // Note: This should remain the last member so it'll be destroyed and 832 // invalidate its weak pointers before any other members are destroyed. 833 base::WeakPtrFactory<PowerManagerClientStubImpl> weak_ptr_factory_; 834}; 835 836PowerManagerClient::PowerManagerClient() { 837} 838 839PowerManagerClient::~PowerManagerClient() { 840} 841 842// static 843PowerManagerClient* PowerManagerClient::Create( 844 DBusClientImplementationType type, 845 dbus::Bus* bus) { 846 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) 847 return new PowerManagerClientImpl(bus); 848 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type); 849 return new PowerManagerClientStubImpl(); 850} 851 852} // namespace chromeos 853