243 lines
9.1 KiB
C++
243 lines
9.1 KiB
C++
/*
|
|
* Copyright 2022 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "remote_name_request.h"
|
|
|
|
#include <optional>
|
|
#include <queue>
|
|
#include <unordered_set>
|
|
#include <variant>
|
|
|
|
#include "hci/acl_manager/acl_scheduler.h"
|
|
#include "hci/acl_manager/event_checkers.h"
|
|
#include "hci/hci_layer.h"
|
|
|
|
namespace bluetooth {
|
|
namespace hci {
|
|
|
|
struct RemoteNameRequestModule::impl {
|
|
public:
|
|
impl(const RemoteNameRequestModule& module) : module_(module) {}
|
|
|
|
void Start() {
|
|
LOG_INFO("Starting RemoteNameRequestModule");
|
|
hci_layer_ = module_.GetDependency<HciLayer>();
|
|
acl_scheduler_ = module_.GetDependency<acl_manager::AclScheduler>();
|
|
handler_ = module_.GetHandler();
|
|
|
|
hci_layer_->RegisterEventHandler(
|
|
EventCode::REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION,
|
|
handler_->BindOn(
|
|
this, &RemoteNameRequestModule::impl::on_remote_host_supported_features_notification));
|
|
hci_layer_->RegisterEventHandler(
|
|
EventCode::REMOTE_NAME_REQUEST_COMPLETE,
|
|
handler_->BindOn(this, &RemoteNameRequestModule::impl::on_remote_name_request_complete));
|
|
}
|
|
|
|
void Stop() {
|
|
LOG_INFO("Stopping RemoteNameRequestModule");
|
|
hci_layer_->UnregisterEventHandler(EventCode::REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION);
|
|
hci_layer_->UnregisterEventHandler(EventCode::REMOTE_NAME_REQUEST_COMPLETE);
|
|
}
|
|
|
|
void StartRemoteNameRequest(
|
|
Address address,
|
|
std::unique_ptr<RemoteNameRequestBuilder> request,
|
|
CompletionCallback on_completion,
|
|
RemoteHostSupportedFeaturesCallback on_remote_host_supported_features_notification,
|
|
RemoteNameCallback on_remote_name_complete) {
|
|
LOG_INFO("Enqueuing remote name request to %s", address.ToRedactedStringForLogging().c_str());
|
|
|
|
// This callback needs to be shared between the *start* callback and the *cancel_completed*
|
|
// callback, so we refcount it for safety. But since the scheduler guarantees that exactly one
|
|
// of these callbacks will be invokes, this is safe.
|
|
auto on_remote_name_complete_ptr =
|
|
std::make_shared<RemoteNameCallback>(std::move(on_remote_name_complete));
|
|
|
|
acl_scheduler_->EnqueueRemoteNameRequest(
|
|
address,
|
|
handler_->BindOnceOn(
|
|
this,
|
|
&impl::actually_start_remote_name_request,
|
|
address,
|
|
std::move(request),
|
|
std::move(on_completion),
|
|
std::move(on_remote_host_supported_features_notification),
|
|
on_remote_name_complete_ptr),
|
|
handler_->BindOnce(
|
|
[&](Address address, std::shared_ptr<RemoteNameCallback> on_remote_name_complete_ptr) {
|
|
LOG_INFO(
|
|
"Dequeued remote name request to %s since it was cancelled",
|
|
address.ToRedactedStringForLogging().c_str());
|
|
on_remote_name_complete_ptr->Invoke(ErrorCode::PAGE_TIMEOUT, {});
|
|
},
|
|
address,
|
|
on_remote_name_complete_ptr));
|
|
}
|
|
|
|
void CancelRemoteNameRequest(Address address) {
|
|
LOG_INFO(
|
|
"Enqueuing cancel of remote name request to %s",
|
|
address.ToRedactedStringForLogging().c_str());
|
|
acl_scheduler_->CancelRemoteNameRequest(
|
|
address, handler_->BindOnceOn(this, &impl::actually_cancel_remote_name_request, address));
|
|
}
|
|
|
|
void ReportRemoteNameRequestCancellation(Address address) {
|
|
if (pending_) {
|
|
LOG_INFO(
|
|
"Received CONNECTION_COMPLETE (corresponding INCORRECTLY to an RNR cancellation) from %s",
|
|
address.ToRedactedStringForLogging().c_str());
|
|
pending_ = false;
|
|
on_remote_name_complete_.Invoke(ErrorCode::UNKNOWN_CONNECTION, {});
|
|
acl_scheduler_->ReportRemoteNameRequestCompletion(address);
|
|
} else {
|
|
LOG_ERROR(
|
|
"Received unexpected CONNECTION_COMPLETE when no Remote Name Request OR ACL connection "
|
|
"is outstanding");
|
|
}
|
|
}
|
|
|
|
private:
|
|
void actually_start_remote_name_request(
|
|
Address address,
|
|
std::unique_ptr<RemoteNameRequestBuilder> request,
|
|
CompletionCallback on_completion,
|
|
RemoteHostSupportedFeaturesCallback on_remote_host_supported_features_notification,
|
|
std::shared_ptr<RemoteNameCallback> on_remote_name_complete_ptr) {
|
|
LOG_INFO("Starting remote name request to %s", address.ToRedactedStringForLogging().c_str());
|
|
ASSERT(pending_ == false);
|
|
pending_ = true;
|
|
on_remote_host_supported_features_notification_ =
|
|
std::move(on_remote_host_supported_features_notification);
|
|
on_remote_name_complete_ = std::move(*on_remote_name_complete_ptr.get());
|
|
hci_layer_->EnqueueCommand(
|
|
std::move(request),
|
|
handler_->BindOnceOn(
|
|
this, &impl::on_start_remote_name_request_status, address, std::move(on_completion)));
|
|
}
|
|
|
|
void on_start_remote_name_request_status(
|
|
Address address, CompletionCallback on_completion, CommandStatusView status) {
|
|
ASSERT(pending_ == true);
|
|
ASSERT(status.GetCommandOpCode() == OpCode::REMOTE_NAME_REQUEST);
|
|
LOG_INFO(
|
|
"Got status %hhu when starting remote name request to to %s",
|
|
status.GetStatus(),
|
|
address.ToString().c_str());
|
|
on_completion.Invoke(status.GetStatus());
|
|
if (status.GetStatus() != ErrorCode::SUCCESS /* pending */) {
|
|
pending_ = false;
|
|
acl_scheduler_->ReportRemoteNameRequestCompletion(address);
|
|
}
|
|
}
|
|
|
|
void actually_cancel_remote_name_request(Address address) {
|
|
ASSERT(pending_ == true);
|
|
LOG_INFO("Cancelling remote name request to %s", address.ToRedactedStringForLogging().c_str());
|
|
hci_layer_->EnqueueCommand(
|
|
RemoteNameRequestCancelBuilder::Create(address),
|
|
handler_->BindOnce(
|
|
&acl_manager::check_command_complete<RemoteNameRequestCancelCompleteView>));
|
|
}
|
|
|
|
void on_remote_host_supported_features_notification(EventView view) {
|
|
auto packet = RemoteHostSupportedFeaturesNotificationView::Create(view);
|
|
ASSERT(packet.IsValid());
|
|
if (pending_) {
|
|
LOG_INFO(
|
|
"Received REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION from %s",
|
|
packet.GetBdAddr().ToRedactedStringForLogging().c_str());
|
|
on_remote_host_supported_features_notification_.Invoke(packet.GetHostSupportedFeatures());
|
|
} else {
|
|
LOG_ERROR(
|
|
"Received unexpected REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION when no Remote Name "
|
|
"Request is outstanding");
|
|
}
|
|
}
|
|
|
|
void on_remote_name_request_complete(EventView view) {
|
|
auto packet = RemoteNameRequestCompleteView::Create(view);
|
|
ASSERT(packet.IsValid());
|
|
if (pending_) {
|
|
LOG_INFO(
|
|
"Received REMOTE_NAME_REQUEST_COMPLETE from %s",
|
|
packet.GetBdAddr().ToRedactedStringForLogging().c_str());
|
|
pending_ = false;
|
|
on_remote_name_complete_.Invoke(packet.GetStatus(), packet.GetRemoteName());
|
|
acl_scheduler_->ReportRemoteNameRequestCompletion(packet.GetBdAddr());
|
|
} else {
|
|
LOG_ERROR(
|
|
"Received unexpected REMOTE_NAME_REQUEST_COMPLETE when no Remote Name Request is "
|
|
"outstanding");
|
|
}
|
|
}
|
|
|
|
const RemoteNameRequestModule& module_;
|
|
HciLayer* hci_layer_;
|
|
acl_manager::AclScheduler* acl_scheduler_;
|
|
os::Handler* handler_;
|
|
|
|
bool pending_ = false;
|
|
RemoteHostSupportedFeaturesCallback on_remote_host_supported_features_notification_;
|
|
RemoteNameCallback on_remote_name_complete_;
|
|
};
|
|
|
|
const ModuleFactory RemoteNameRequestModule::Factory =
|
|
ModuleFactory([]() { return new RemoteNameRequestModule(); });
|
|
|
|
RemoteNameRequestModule::RemoteNameRequestModule() : pimpl_(std::make_unique<impl>(*this)){};
|
|
RemoteNameRequestModule::~RemoteNameRequestModule() = default;
|
|
|
|
void RemoteNameRequestModule::StartRemoteNameRequest(
|
|
Address address,
|
|
std::unique_ptr<RemoteNameRequestBuilder> request,
|
|
CompletionCallback on_completion,
|
|
RemoteHostSupportedFeaturesCallback on_remote_host_supported_features_notification,
|
|
RemoteNameCallback on_remote_name_complete) {
|
|
CallOn(
|
|
pimpl_.get(),
|
|
&impl::StartRemoteNameRequest,
|
|
address,
|
|
std::move(request),
|
|
std::move(on_completion),
|
|
std::move(on_remote_host_supported_features_notification),
|
|
std::move(on_remote_name_complete));
|
|
}
|
|
|
|
void RemoteNameRequestModule::CancelRemoteNameRequest(Address address) {
|
|
CallOn(pimpl_.get(), &impl::CancelRemoteNameRequest, address);
|
|
}
|
|
|
|
void RemoteNameRequestModule::ReportRemoteNameRequestCancellation(Address address) {
|
|
CallOn(pimpl_.get(), &impl::ReportRemoteNameRequestCancellation, address);
|
|
}
|
|
|
|
void RemoteNameRequestModule::ListDependencies(ModuleList* list) const {
|
|
list->add<HciLayer>();
|
|
list->add<acl_manager::AclScheduler>();
|
|
}
|
|
|
|
void RemoteNameRequestModule::Start() {
|
|
pimpl_->Start();
|
|
}
|
|
|
|
void RemoteNameRequestModule::Stop() {
|
|
pimpl_->Stop();
|
|
}
|
|
|
|
} // namespace hci
|
|
} // namespace bluetooth
|