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