GoogleGit

blob: 4106b62576bce8780357b62d6c7a0fc63e598d4d [file] [log] [blame]
  1. // Copyright (c) 2012 The Chromium OS 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. #include <base/at_exit.h>
  5. #include <base/bind.h>
  6. #include <base/command_line.h>
  7. #include <base/logging.h>
  8. #include <base/memory/ref_counted.h>
  9. #include <base/message_loop/message_loop.h>
  10. #include <base/time/time.h>
  11. #include <chromeos/dbus/service_constants.h>
  12. #include <chromeos/flag_helper.h>
  13. #include <dbus/bus.h>
  14. #include <dbus/message.h>
  15. #include <dbus/object_proxy.h>
  16. #include "power_manager/proto_bindings/suspend.pb.h"
  17. namespace {
  18. // Human-readable description of the delay's purpose.
  19. const char kSuspendDelayDescription[] = "suspend_delay_sample";
  20. } // namespace
  21. // Passes |request| to powerd's |method_name| D-Bus method.
  22. // Copies the returned protocol buffer to |reply_out|, which may be NULL if no
  23. // reply is expected.
  24. bool CallMethod(dbus::ObjectProxy* powerd_proxy,
  25. const std::string& method_name,
  26. const google::protobuf::MessageLite& request,
  27. google::protobuf::MessageLite* reply_out) {
  28. LOG(INFO) << "Calling " << method_name << " method";
  29. dbus::MethodCall method_call(
  30. power_manager::kPowerManagerInterface, method_name);
  31. dbus::MessageWriter writer(&method_call);
  32. writer.AppendProtoAsArrayOfBytes(request);
  33. scoped_ptr<dbus::Response> response(
  34. powerd_proxy->CallMethodAndBlock(
  35. &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
  36. if (!response)
  37. return false;
  38. if (!reply_out)
  39. return true;
  40. dbus::MessageReader reader(response.get());
  41. CHECK(reader.PopArrayOfBytesAsProto(reply_out))
  42. << "Unable to parse response from call to " << method_name;
  43. return true;
  44. }
  45. // Registers a suspend delay and returns the corresponding ID.
  46. int RegisterSuspendDelay(dbus::ObjectProxy* powerd_proxy,
  47. int timeout_ms) {
  48. power_manager::RegisterSuspendDelayRequest request;
  49. request.set_timeout(
  50. base::TimeDelta::FromMilliseconds(timeout_ms).ToInternalValue());
  51. request.set_description(kSuspendDelayDescription);
  52. power_manager::RegisterSuspendDelayReply reply;
  53. CHECK(CallMethod(powerd_proxy, power_manager::kRegisterSuspendDelayMethod,
  54. request, &reply));
  55. LOG(INFO) << "Registered delay " << reply.delay_id();
  56. return reply.delay_id();
  57. }
  58. // Announces that the process is ready for suspend attempt |suspend_id|.
  59. void SendSuspendReady(scoped_refptr<dbus::ObjectProxy> powerd_proxy,
  60. int delay_id,
  61. int suspend_id) {
  62. LOG(INFO) << "Announcing readiness of delay " << delay_id
  63. << " for suspend attempt " << suspend_id;
  64. power_manager::SuspendReadinessInfo request;
  65. request.set_delay_id(delay_id);
  66. request.set_suspend_id(suspend_id);
  67. CallMethod(powerd_proxy.get(), power_manager::kHandleSuspendReadinessMethod,
  68. request, NULL);
  69. }
  70. // Handles the start of a suspend attempt. Posts a task to run
  71. // SendSuspendReady() after a delay.
  72. void HandleSuspendImminent(scoped_refptr<dbus::ObjectProxy> powerd_proxy,
  73. int delay_id,
  74. int delay_ms,
  75. dbus::Signal* signal) {
  76. power_manager::SuspendImminent info;
  77. dbus::MessageReader reader(signal);
  78. CHECK(reader.PopArrayOfBytesAsProto(&info));
  79. int suspend_id = info.suspend_id();
  80. LOG(INFO) << "Got notification about suspend attempt " << suspend_id;
  81. LOG(INFO) << "Sleeping " << delay_ms << " ms before responding";
  82. base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
  83. base::Bind(&SendSuspendReady, powerd_proxy, delay_id, suspend_id),
  84. base::TimeDelta::FromMilliseconds(delay_ms));
  85. }
  86. // Handles the completion of a suspend attempt.
  87. void HandleSuspendDone(dbus::Signal* signal) {
  88. power_manager::SuspendDone info;
  89. dbus::MessageReader reader(signal);
  90. CHECK(reader.PopArrayOfBytesAsProto(&info));
  91. const base::TimeDelta duration =
  92. base::TimeDelta::FromInternalValue(info.suspend_duration());
  93. LOG(INFO) << "Suspend attempt " << info.suspend_id() << " is complete; "
  94. << "system was suspended for " << duration.InMilliseconds()
  95. << " ms";
  96. }
  97. // Handles the result of an attempt to connect to a D-Bus signal.
  98. void DBusSignalConnected(const std::string& interface,
  99. const std::string& signal,
  100. bool success) {
  101. CHECK(success) << "Unable to connect to " << interface << "." << signal;
  102. }
  103. int main(int argc, char* argv[]) {
  104. DEFINE_int32(delay_ms, 5000,
  105. "Milliseconds to wait before reporting suspend readiness");
  106. DEFINE_int32(timeout_ms, 7000, "Suspend timeout in milliseconds");
  107. chromeos::FlagHelper::Init(argc, argv,
  108. "Exercise powerd's functionality that permits other processes to\n"
  109. "perform last-minute work before the system suspends.");
  110. base::AtExitManager at_exit_manager;
  111. base::MessageLoopForIO message_loop;
  112. dbus::Bus::Options options;
  113. options.bus_type = dbus::Bus::SYSTEM;
  114. scoped_refptr<dbus::Bus> bus(new dbus::Bus(options));
  115. CHECK(bus->Connect());
  116. dbus::ObjectProxy* powerd_proxy = bus->GetObjectProxy(
  117. power_manager::kPowerManagerServiceName,
  118. dbus::ObjectPath(power_manager::kPowerManagerServicePath));
  119. const int delay_id = RegisterSuspendDelay(powerd_proxy, FLAGS_timeout_ms);
  120. powerd_proxy->ConnectToSignal(
  121. power_manager::kPowerManagerInterface,
  122. power_manager::kSuspendImminentSignal,
  123. base::Bind(&HandleSuspendImminent, make_scoped_refptr(powerd_proxy),
  124. delay_id, FLAGS_delay_ms),
  125. base::Bind(&DBusSignalConnected));
  126. powerd_proxy->ConnectToSignal(
  127. power_manager::kPowerManagerInterface,
  128. power_manager::kSuspendDoneSignal,
  129. base::Bind(&HandleSuspendDone),
  130. base::Bind(&DBusSignalConnected));
  131. message_loop.Run();
  132. // powerd will automatically unregister this process's suspend delay when the
  133. // process disconnects from D-Bus.
  134. return 0;
  135. }