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