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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/ash/components/tether/message_transfer_operation.h"
#include <memory>
#include <set>
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "chromeos/ash/components/multidevice/logging/logging.h"
#include "chromeos/ash/components/tether/message_wrapper.h"
#include "chromeos/ash/components/timer_factory/timer_factory_impl.h"
namespace ash::tether {
MessageTransferOperation::MessageTransferOperation(
const TetherHost& tether_host,
HostConnection::Factory::ConnectionPriority connection_priority,
raw_ptr<HostConnection::Factory> host_connection_factory)
: tether_host_(tether_host),
connection_priority_(connection_priority),
host_connection_factory_(host_connection_factory),
timer_factory_(ash::timer_factory::TimerFactoryImpl::Factory::Create()) {}
MessageTransferOperation::~MessageTransferOperation() {
// If initialization never occurred, devices were never registered.
if (!initialized_) {
return;
}
shutting_down_ = true;
// Stop the operation if it's in flight, as the operation itself
// will be destroyed.
StopOperation();
}
void MessageTransferOperation::Initialize() {
if (initialized_) {
return;
}
initialized_ = true;
// Store the message type for this connection as a private field. This is
// necessary because when UnregisterDevice() is called in the destructor, the
// derived class has already been destroyed, so invoking
// GetMessageTypeForConnection() will fail due to it being a pure virtual
// function at that time.
message_type_for_connection_ = GetMessageTypeForConnection();
OnOperationStarted();
StartConnectionTimerForDevice();
host_connection_factory_->Create(
tether_host_, connection_priority_, /*payload_listener=*/this,
base::BindOnce(&MessageTransferOperation::OnDisconnected,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&MessageTransferOperation::OnConnectionAttemptComplete,
weak_ptr_factory_.GetWeakPtr()));
}
void MessageTransferOperation::StopOperation() {
// Note: This function may be called from the destructor. It is invalid to
// invoke any virtual methods if |shutting_down_| is true.
StopTimerForDeviceIfRunning();
host_connection_.reset();
if (!shutting_down_) {
OnOperationFinished();
}
}
void MessageTransferOperation::SendMessage(
std::unique_ptr<MessageWrapper> message_wrapper,
HostConnection::OnMessageSentCallback on_message_sent) {
CHECK(host_connection_);
host_connection_->SendMessage(std::move(message_wrapper),
std::move(on_message_sent));
}
uint32_t MessageTransferOperation::GetMessageTimeoutSeconds() {
return MessageTransferOperation::kDefaultMessageTimeoutSeconds;
}
void MessageTransferOperation::OnConnectionAttemptComplete(
std::unique_ptr<HostConnection> host_connection) {
if (!host_connection) {
PA_LOG(WARNING) << "Failed to connect to device ["
<< GetDeviceId(/*truncate_for_logs=*/true) << "].";
StopOperation();
} else {
host_connection_ = std::move(host_connection);
// Stop the timer which was started from StartConnectionTimerForDevice()
// since the connection has now been established. Start another timer now
// via StartMessageTimerForDevice() while waiting for messages to be sent to
// and received by |remote_device|.
StopTimerForDeviceIfRunning();
StartMessageTimerForDevice();
PA_LOG(INFO) << "Successfully opened connection to ["
<< GetDeviceId(/*truncate_for_logs=*/true) << "].";
OnDeviceAuthenticated();
}
}
void MessageTransferOperation::OnDisconnected() {
PA_LOG(VERBOSE) << "Remote device disconnected from this device: "
<< GetDeviceId(/*truncate_for_logs=*/true);
StopOperation();
}
void MessageTransferOperation::StartConnectionTimerForDevice() {
StartTimerForDevice(kConnectionTimeoutSeconds);
}
void MessageTransferOperation::StartMessageTimerForDevice() {
StartTimerForDevice(GetMessageTimeoutSeconds());
}
void MessageTransferOperation::StartTimerForDevice(uint32_t timeout_seconds) {
PA_LOG(VERBOSE) << "Starting timer for operation with message type "
<< message_type_for_connection_ << " from device with ID "
<< GetDeviceId(/*truncate_for_logs=*/true) << ".";
remote_device_timer_ = timer_factory_->CreateOneShotTimer();
remote_device_timer_->Start(
FROM_HERE, base::Seconds(timeout_seconds),
base::BindOnce(&MessageTransferOperation::OnTimeout,
weak_ptr_factory_.GetWeakPtr()));
}
void MessageTransferOperation::StopTimerForDeviceIfRunning() {
if (!remote_device_timer_) {
return;
}
remote_device_timer_->Stop();
remote_device_timer_.reset();
}
void MessageTransferOperation::OnTimeout() {
PA_LOG(WARNING) << "Timed out operation for message type "
<< message_type_for_connection_ << " from device with ID "
<< GetDeviceId(/*truncate_for_logs=*/true) << ".";
remote_device_timer_.reset();
StopOperation();
}
void MessageTransferOperation::SetTimerFactoryForTest(
std::unique_ptr<ash::timer_factory::TimerFactory> timer_factory_for_test) {
timer_factory_ = std::move(timer_factory_for_test);
}
const std::string MessageTransferOperation::GetDeviceId(
bool truncate_for_logs) const {
if (truncate_for_logs) {
return tether_host_.GetTruncatedDeviceIdForLogs();
} else {
return tether_host_.GetDeviceId();
}
}
} // namespace ash::tether
|