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
AsyncEventSequencer()11 AsyncEventSequencer::AsyncEventSequencer() {
12 }
~AsyncEventSequencer()13 AsyncEventSequencer::~AsyncEventSequencer() {
14 }
15
GetHandler(const std::string & descriptive_message,bool failure_is_fatal)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
GetExportHandler(const std::string & interface_name,const std::string & method_name,const std::string & descriptive_message,bool failure_is_fatal)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
OnAllTasksCompletedCall(std::vector<CompletionAction> actions)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 {
IgnoreSuccess(const AsyncEventSequencer::CompletionTask & task,bool)52 void IgnoreSuccess(const AsyncEventSequencer::CompletionTask& task,
53 bool /*success*/) {
54 task.Run();
55 }
DoNothing(bool)56 void DoNothing(bool /* success */) {
57 }
58 } // namespace
59
WrapCompletionTask(const CompletionTask & task)60 AsyncEventSequencer::CompletionAction AsyncEventSequencer::WrapCompletionTask(
61 const CompletionTask& task) {
62 return base::Bind(&IgnoreSuccess, task);
63 }
64
65 AsyncEventSequencer::CompletionAction
GetDefaultCompletionAction()66 AsyncEventSequencer::GetDefaultCompletionAction() {
67 return base::Bind(&DoNothing);
68 }
69
HandleFinish(int registration_number,const std::string & error_message,bool failure_is_fatal,bool success)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
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)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
RetireRegistration(int registration_number)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
CheckForFailure(bool failure_is_fatal,bool success,const std::string & error_message)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
PossiblyRunCompletionActions()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