aboutsummaryrefslogtreecommitdiffstats
path: root/chromeos/dbus/async_event_sequencer.cc
blob: 33cf9ceb64de4fd5dc770647bcb1527ca2f85a6c (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
// 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 <chromeos/dbus/async_event_sequencer.h>

namespace chromeos {

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(); }
}  // namespace

AsyncEventSequencer::CompletionAction AsyncEventSequencer::WrapCompletionTask(
    const CompletionTask& task) {
  return base::Bind(&IgnoreSuccess, task);
}

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(1, 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 chromeos