blob: 16a7d5b03bb522d83ace582a55aee8f88c8dd9eb [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <dbus/dbus-glib-lowlevel.h>
#include <gflags/gflags.h>
#include "base/bind.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "base/time.h"
#include "chromeos/dbus/dbus.h"
#include "chromeos/dbus/service_constants.h"
#include "power_manager/common/dbus_handler.h"
#include "power_manager/common/util_dbus.h"
#include "power_manager/suspend.pb.h"
DEFINE_int32(delay_ms, 5000,
"Milliseconds to wait before reporting suspend readiness");
DEFINE_int32(timeout_ms, 7000, "Suspend timeout in milliseconds");
namespace {
// Human-readable description of the delay's purpose.
const char kSuspendDelayDescription[] = "suspend_delay_sample";
// ID corresponding to the current suspend attempt.
int suspend_id = 0;
// ID corresponding to the registered suspend delay.
int delay_id = 0;
} // namespace
power_manager::util::DBusHandler dbus_handler;
// Passes |request| to powerd's |method_name| D-Bus method.
// Copies the returned protocol buffer to |reply_out|, which may be NULL if no
// reply is expected.
bool CallMethod(const std::string& method_name,
const google::protobuf::MessageLite& request,
google::protobuf::MessageLite* reply_out) {
LOG(INFO) << "Calling " << method_name << " method";
DBusConnection* connection = dbus_g_connection_get_connection(
chromeos::dbus::GetSystemBusConnection().g_connection());
CHECK(connection);
DBusMessage* message = dbus_message_new_method_call(
power_manager::kPowerManagerServiceName,
power_manager::kPowerManagerServicePath,
power_manager::kPowerManagerInterface,
method_name.c_str());
CHECK(message);
power_manager::util::AppendProtocolBufferToDBusMessage(request, message);
DBusError error;
dbus_error_init(&error);
DBusMessage* response = dbus_connection_send_with_reply_and_block(
connection, message, DBUS_TIMEOUT_USE_DEFAULT, &error);
dbus_message_unref(message);
CHECK(!dbus_error_is_set(&error))
<< "Call to " << method_name << " failed: " << error.name
<< " (" << error.message << ")";
CHECK(!reply_out ||
power_manager::util::ParseProtocolBufferFromDBusMessage(
response, reply_out))
<< "Unable to parse response from call to " << method_name;
dbus_message_unref(response);
return true;
}
void RegisterSuspendDelay() {
power_manager::RegisterSuspendDelayRequest request;
request.set_timeout(
base::TimeDelta::FromMilliseconds(FLAGS_timeout_ms).ToInternalValue());
request.set_description(kSuspendDelayDescription);
power_manager::RegisterSuspendDelayReply reply;
CHECK(CallMethod(power_manager::kRegisterSuspendDelayMethod,
request, &reply));
delay_id = reply.delay_id();
LOG(INFO) << "Registered delay with ID " << delay_id;
}
gboolean SendSuspendReady(gpointer) {
LOG(INFO) << "Calling " << power_manager::kHandleSuspendReadinessMethod;
power_manager::SuspendReadinessInfo request;
request.set_delay_id(delay_id);
request.set_suspend_id(suspend_id);
CallMethod(power_manager::kHandleSuspendReadinessMethod, request, NULL);
return FALSE;
}
bool SuspendDelaySignaled(DBusMessage* message) {
power_manager::SuspendImminent info;
CHECK(power_manager::util::ParseProtocolBufferFromDBusMessage(message,
&info));
suspend_id = info.suspend_id();
LOG(INFO) << "Got notification about suspend with ID " << suspend_id;
LOG(INFO) << "Sleeping " << FLAGS_delay_ms << " ms before responding";
g_timeout_add(FLAGS_delay_ms, SendSuspendReady, NULL);
return true;
}
void RegisterDBusMessageHandler() {
dbus_handler.AddSignalHandler(
power_manager::kPowerManagerInterface,
power_manager::kSuspendImminentSignal,
base::Bind(&SuspendDelaySignaled));
dbus_handler.Start();
}
int main(int argc, char* argv[]) {
g_type_init();
google::ParseCommandLineFlags(&argc, &argv, true);
GMainLoop* loop = g_main_loop_new(NULL, false);
RegisterDBusMessageHandler();
RegisterSuspendDelay();
g_main_loop_run(loop);
return 0;
}