1 // Copyright 2014 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 5 #include <brillo/dbus/async_event_sequencer.h> 6 7 namespace brillo { 8 9 namespace dbus_utils { 10 11 AsyncEventSequencer::AsyncEventSequencer() { 12 } 13 AsyncEventSequencer::~AsyncEventSequencer() { 14 } 15 16 AsyncEventSequencer::Handler AsyncEventSequencer::GetHandler( 17 const std::string& descriptive_message, 18 bool failure_is_fatal) { 19 CHECK(!started_) << "Cannot create handlers after OnAllTasksCompletedCall()"; 20 int unique_registration_id = ++registration_counter_; 21 outstanding_registrations_.insert(unique_registration_id); 22 return base::Bind(&AsyncEventSequencer::HandleFinish, 23 this, 24 unique_registration_id, 25 descriptive_message, 26 failure_is_fatal); 27 } 28 29 AsyncEventSequencer::ExportHandler AsyncEventSequencer::GetExportHandler( 30 const std::string& interface_name, 31 const std::string& method_name, 32 const std::string& descriptive_message, 33 bool failure_is_fatal) { 34 auto finish_handler = GetHandler(descriptive_message, failure_is_fatal); 35 return base::Bind(&AsyncEventSequencer::HandleDBusMethodExported, 36 this, 37 finish_handler, 38 interface_name, 39 method_name); 40 } 41 42 void AsyncEventSequencer::OnAllTasksCompletedCall( 43 std::vector<CompletionAction> actions) { 44 CHECK(!started_) << "OnAllTasksCompletedCall called twice!"; 45 started_ = true; 46 completion_actions_.assign(actions.begin(), actions.end()); 47 // All of our callbacks might have been called already. 48 PossiblyRunCompletionActions(); 49 } 50 51 namespace { 52 void IgnoreSuccess(const AsyncEventSequencer::CompletionTask& task, 53 bool /*success*/) { 54 task.Run(); 55 } 56 void DoNothing(bool /* success */) { 57 } 58 } // namespace 59 60 AsyncEventSequencer::CompletionAction AsyncEventSequencer::WrapCompletionTask( 61 const CompletionTask& task) { 62 return base::Bind(&IgnoreSuccess, task); 63 } 64 65 AsyncEventSequencer::CompletionAction 66 AsyncEventSequencer::GetDefaultCompletionAction() { 67 return base::Bind(&DoNothing); 68 } 69 70 void AsyncEventSequencer::HandleFinish(int registration_number, 71 const std::string& error_message, 72 bool failure_is_fatal, 73 bool success) { 74 RetireRegistration(registration_number); 75 CheckForFailure(failure_is_fatal, success, error_message); 76 PossiblyRunCompletionActions(); 77 } 78 79 void AsyncEventSequencer::HandleDBusMethodExported( 80 const AsyncEventSequencer::Handler& finish_handler, 81 const std::string& expected_interface_name, 82 const std::string& expected_method_name, 83 const std::string& actual_interface_name, 84 const std::string& actual_method_name, 85 bool success) { 86 CHECK_EQ(expected_method_name, actual_method_name) 87 << "Exported DBus method '" << actual_method_name << "' " 88 << "but expected '" << expected_method_name << "'"; 89 CHECK_EQ(expected_interface_name, actual_interface_name) 90 << "Exported method DBus interface '" << actual_interface_name << "' " 91 << "but expected '" << expected_interface_name << "'"; 92 finish_handler.Run(success); 93 } 94 95 void AsyncEventSequencer::RetireRegistration(int registration_number) { 96 const size_t handlers_retired = 97 outstanding_registrations_.erase(registration_number); 98 CHECK_EQ(1U, handlers_retired) << "Tried to retire invalid handler " 99 << registration_number << ")"; 100 } 101 102 void AsyncEventSequencer::CheckForFailure(bool failure_is_fatal, 103 bool success, 104 const std::string& error_message) { 105 if (failure_is_fatal) { 106 CHECK(success) << error_message; 107 } 108 if (!success) { 109 LOG(ERROR) << error_message; 110 had_failures_ = true; 111 } 112 } 113 114 void AsyncEventSequencer::PossiblyRunCompletionActions() { 115 if (!started_ || !outstanding_registrations_.empty()) { 116 // Don't run completion actions if we have any outstanding 117 // Handlers outstanding or if any more handlers might 118 // be scheduled in the future. 119 return; 120 } 121 for (const auto& completion_action : completion_actions_) { 122 // Should this be put on the message loop or run directly? 123 completion_action.Run(!had_failures_); 124 } 125 // Discard our references to those actions. 126 completion_actions_.clear(); 127 } 128 129 } // namespace dbus_utils 130 131 } // namespace brillo 132