aboutsummaryrefslogtreecommitdiff
path: root/brillo/dbus/async_event_sequencer.cc
blob: 8861e216ebbe7e3c9a80dc6569a0aee47e08d4da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// 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