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