// 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> 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