13ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley// Copyright 2014 The Chromium OS Authors. All rights reserved.
23ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley// Use of this source code is governed by a BSD-style license that can be
33ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley// found in the LICENSE file.
43ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley
59ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/dbus/async_event_sequencer.h>
63ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley
79ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenkonamespace brillo {
83ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley
93ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wileynamespace dbus_utils {
103ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley
1105d29044d14a60775ed6c51c75a414eb0cb50347Alex VakulenkoAsyncEventSequencer::AsyncEventSequencer() {
1205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko}
1305d29044d14a60775ed6c51c75a414eb0cb50347Alex VakulenkoAsyncEventSequencer::~AsyncEventSequencer() {
1405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko}
153ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley
163ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher WileyAsyncEventSequencer::Handler AsyncEventSequencer::GetHandler(
1705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    const std::string& descriptive_message,
1805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    bool failure_is_fatal) {
193ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  CHECK(!started_) << "Cannot create handlers after OnAllTasksCompletedCall()";
203ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  int unique_registration_id = ++registration_counter_;
213ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  outstanding_registrations_.insert(unique_registration_id);
2205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  return base::Bind(&AsyncEventSequencer::HandleFinish,
2305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                    this,
2405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                    unique_registration_id,
2505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                    descriptive_message,
263ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley                    failure_is_fatal);
273ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley}
283ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley
293ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher WileyAsyncEventSequencer::ExportHandler AsyncEventSequencer::GetExportHandler(
3005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    const std::string& interface_name,
3105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    const std::string& method_name,
3205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    const std::string& descriptive_message,
3305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    bool failure_is_fatal) {
343ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  auto finish_handler = GetHandler(descriptive_message, failure_is_fatal);
3505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  return base::Bind(&AsyncEventSequencer::HandleDBusMethodExported,
3605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                    this,
373ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley                    finish_handler,
383ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley                    interface_name,
393ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley                    method_name);
403ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley}
413ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley
423ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wileyvoid AsyncEventSequencer::OnAllTasksCompletedCall(
433ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley    std::vector<CompletionAction> actions) {
443ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  CHECK(!started_) << "OnAllTasksCompletedCall called twice!";
453ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  started_ = true;
463ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  completion_actions_.assign(actions.begin(), actions.end());
473ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  // All of our callbacks might have been called already.
483ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  PossiblyRunCompletionActions();
493ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley}
503ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley
513ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wileynamespace {
523ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wileyvoid IgnoreSuccess(const AsyncEventSequencer::CompletionTask& task,
5305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                   bool /*success*/) {
5405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  task.Run();
5505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko}
562fd46ba1458275cd16b0949675bff70cc8abcdadChristopher Wileyvoid DoNothing(bool /* success */) {
5705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko}
583ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley}  // namespace
593ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley
603ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher WileyAsyncEventSequencer::CompletionAction AsyncEventSequencer::WrapCompletionTask(
613ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley    const CompletionTask& task) {
623ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  return base::Bind(&IgnoreSuccess, task);
633ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley}
643ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley
6590e4ffc22f8eaeb8284b30e22474d77aa1ba1557Alex VakulenkoAsyncEventSequencer::CompletionAction
6605d29044d14a60775ed6c51c75a414eb0cb50347Alex VakulenkoAsyncEventSequencer::GetDefaultCompletionAction() {
6790e4ffc22f8eaeb8284b30e22474d77aa1ba1557Alex Vakulenko  return base::Bind(&DoNothing);
6890e4ffc22f8eaeb8284b30e22474d77aa1ba1557Alex Vakulenko}
6990e4ffc22f8eaeb8284b30e22474d77aa1ba1557Alex Vakulenko
703ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wileyvoid AsyncEventSequencer::HandleFinish(int registration_number,
713ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley                                       const std::string& error_message,
7205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                       bool failure_is_fatal,
7305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                       bool success) {
743ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  RetireRegistration(registration_number);
753ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  CheckForFailure(failure_is_fatal, success, error_message);
763ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  PossiblyRunCompletionActions();
773ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley}
783ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley
793ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wileyvoid AsyncEventSequencer::HandleDBusMethodExported(
803ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley    const AsyncEventSequencer::Handler& finish_handler,
813ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley    const std::string& expected_interface_name,
823ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley    const std::string& expected_method_name,
833ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley    const std::string& actual_interface_name,
8405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    const std::string& actual_method_name,
8505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    bool success) {
863ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  CHECK_EQ(expected_method_name, actual_method_name)
873ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley      << "Exported DBus method '" << actual_method_name << "' "
883ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley      << "but expected '" << expected_method_name << "'";
893ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  CHECK_EQ(expected_interface_name, actual_interface_name)
903ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley      << "Exported method DBus interface '" << actual_interface_name << "' "
913ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley      << "but expected '" << expected_interface_name << "'";
923ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  finish_handler.Run(success);
933ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley}
943ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley
953ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wileyvoid AsyncEventSequencer::RetireRegistration(int registration_number) {
9605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  const size_t handlers_retired =
9705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      outstanding_registrations_.erase(registration_number);
9805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  CHECK_EQ(1U, handlers_retired) << "Tried to retire invalid handler "
9905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                 << registration_number << ")";
1003ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley}
1013ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley
10205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenkovoid AsyncEventSequencer::CheckForFailure(bool failure_is_fatal,
10305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                          bool success,
1043ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley                                          const std::string& error_message) {
1053ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  if (failure_is_fatal) {
1063ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley    CHECK(success) << error_message;
1073ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  }
1083ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  if (!success) {
1093ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley    LOG(ERROR) << error_message;
1103ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley    had_failures_ = true;
1113ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  }
1123ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley}
1133ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley
1143ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wileyvoid AsyncEventSequencer::PossiblyRunCompletionActions() {
1153ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  if (!started_ || !outstanding_registrations_.empty()) {
1163ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley    // Don't run completion actions if we have any outstanding
1173ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley    // Handlers outstanding or if any more handlers might
1183ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley    // be scheduled in the future.
1193ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley    return;
1203ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  }
1213ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  for (const auto& completion_action : completion_actions_) {
1223ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley    // Should this be put on the message loop or run directly?
1233ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley    completion_action.Run(!had_failures_);
1243ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  }
1253ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  // Discard our references to those actions.
1263ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley  completion_actions_.clear();
1273ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley}
1283ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley
1293ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley}  // namespace dbus_utils
1303ed0af9644cac24bc40bee6cf4b3dd7b063b5b8eChristopher Wiley
1319ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko}  // namespace brillo
132