You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
4.5 KiB
135 lines
4.5 KiB
// Copyright 2014 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 <brillo/dbus/async_event_sequencer.h>
|
|
|
|
#include <base/bind.h>
|
|
#include <base/callback.h>
|
|
|
|
namespace brillo {
|
|
|
|
namespace dbus_utils {
|
|
|
|
AsyncEventSequencer::AsyncEventSequencer() {
|
|
}
|
|
AsyncEventSequencer::~AsyncEventSequencer() {
|
|
}
|
|
|
|
AsyncEventSequencer::Handler AsyncEventSequencer::GetHandler(
|
|
const std::string& descriptive_message,
|
|
bool failure_is_fatal) {
|
|
CHECK(!started_) << "Cannot create handlers after OnAllTasksCompletedCall()";
|
|
int unique_registration_id = ++registration_counter_;
|
|
outstanding_registrations_.insert(unique_registration_id);
|
|
return base::Bind(&AsyncEventSequencer::HandleFinish,
|
|
this,
|
|
unique_registration_id,
|
|
descriptive_message,
|
|
failure_is_fatal);
|
|
}
|
|
|
|
AsyncEventSequencer::ExportHandler AsyncEventSequencer::GetExportHandler(
|
|
const std::string& interface_name,
|
|
const std::string& method_name,
|
|
const std::string& descriptive_message,
|
|
bool failure_is_fatal) {
|
|
auto finish_handler = GetHandler(descriptive_message, failure_is_fatal);
|
|
return base::Bind(&AsyncEventSequencer::HandleDBusMethodExported,
|
|
this,
|
|
finish_handler,
|
|
interface_name,
|
|
method_name);
|
|
}
|
|
|
|
void AsyncEventSequencer::OnAllTasksCompletedCall(
|
|
std::vector<CompletionAction> actions) {
|
|
CHECK(!started_) << "OnAllTasksCompletedCall called twice!";
|
|
started_ = true;
|
|
completion_actions_.assign(actions.begin(), actions.end());
|
|
// All of our callbacks might have been called already.
|
|
PossiblyRunCompletionActions();
|
|
}
|
|
|
|
namespace {
|
|
void IgnoreSuccess(const AsyncEventSequencer::CompletionTask& task,
|
|
bool /*success*/) {
|
|
task.Run();
|
|
}
|
|
void DoNothing(bool /* success */) {
|
|
}
|
|
} // namespace
|
|
|
|
AsyncEventSequencer::CompletionAction AsyncEventSequencer::WrapCompletionTask(
|
|
const CompletionTask& task) {
|
|
return base::Bind(&IgnoreSuccess, task);
|
|
}
|
|
|
|
AsyncEventSequencer::CompletionAction
|
|
AsyncEventSequencer::GetDefaultCompletionAction() {
|
|
return base::Bind(&DoNothing);
|
|
}
|
|
|
|
void AsyncEventSequencer::HandleFinish(int registration_number,
|
|
const std::string& error_message,
|
|
bool failure_is_fatal,
|
|
bool success) {
|
|
RetireRegistration(registration_number);
|
|
CheckForFailure(failure_is_fatal, success, error_message);
|
|
PossiblyRunCompletionActions();
|
|
}
|
|
|
|
void AsyncEventSequencer::HandleDBusMethodExported(
|
|
const AsyncEventSequencer::Handler& finish_handler,
|
|
const std::string& expected_interface_name,
|
|
const std::string& expected_method_name,
|
|
const std::string& actual_interface_name,
|
|
const std::string& actual_method_name,
|
|
bool success) {
|
|
CHECK_EQ(expected_method_name, actual_method_name)
|
|
<< "Exported DBus method '" << actual_method_name << "' "
|
|
<< "but expected '" << expected_method_name << "'";
|
|
CHECK_EQ(expected_interface_name, actual_interface_name)
|
|
<< "Exported method DBus interface '" << actual_interface_name << "' "
|
|
<< "but expected '" << expected_interface_name << "'";
|
|
finish_handler.Run(success);
|
|
}
|
|
|
|
void AsyncEventSequencer::RetireRegistration(int registration_number) {
|
|
const size_t handlers_retired =
|
|
outstanding_registrations_.erase(registration_number);
|
|
CHECK_EQ(1U, handlers_retired) << "Tried to retire invalid handler "
|
|
<< registration_number << ")";
|
|
}
|
|
|
|
void AsyncEventSequencer::CheckForFailure(bool failure_is_fatal,
|
|
bool success,
|
|
const std::string& error_message) {
|
|
if (failure_is_fatal) {
|
|
CHECK(success) << error_message;
|
|
}
|
|
if (!success) {
|
|
LOG(ERROR) << error_message;
|
|
had_failures_ = true;
|
|
}
|
|
}
|
|
|
|
void AsyncEventSequencer::PossiblyRunCompletionActions() {
|
|
if (!started_ || !outstanding_registrations_.empty()) {
|
|
// Don't run completion actions if we have any outstanding
|
|
// Handlers outstanding or if any more handlers might
|
|
// be scheduled in the future.
|
|
return;
|
|
}
|
|
for (const auto& completion_action : completion_actions_) {
|
|
// Should this be put on the message loop or run directly?
|
|
completion_action.Run(!had_failures_);
|
|
}
|
|
// Discard our references to those actions.
|
|
completion_actions_.clear();
|
|
}
|
|
|
|
} // namespace dbus_utils
|
|
|
|
} // namespace brillo
|