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