Home | History | Annotate | Download | only in dbus
      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