blob: cd55679825458f44b8682d1cb9008614f61a2542 [file] [log] [blame]
// Copyright 2021 The Fuchsia 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 "buffer_collection_token_group.h"
#include <lib/ddk/trace/event.h>
#include <lib/fidl/cpp/wire/channel.h>
#include <zircon/errors.h>
#include <zircon/rights.h>
#include "fidl/fuchsia.sysmem/cpp/markers.h"
#include "node.h"
#include "src/devices/sysmem/drivers/sysmem/node_properties.h"
namespace sysmem_driver {
void BufferCollectionTokenGroup::V1::Sync(SyncCompleter::Sync& completer) {
parent_.SyncImpl(ConnectionVersion::kVersion1, completer);
}
void BufferCollectionTokenGroup::V2::Sync(SyncCompleter::Sync& completer) {
parent_.SyncImpl(ConnectionVersion::kVersion2, completer);
}
void BufferCollectionTokenGroup::V1::Close(CloseCompleter::Sync& completer) {
if (!parent_.ReadyForAllocation()) {
parent_.FailSync(FROM_HERE, ConnectionVersion::kVersion1, completer, ZX_ERR_BAD_STATE,
"Close() before AllChildrenPresent()");
return;
}
parent_.ReleaseImpl(ConnectionVersion::kVersion1, completer);
}
void BufferCollectionTokenGroup::V2::Release(ReleaseCompleter::Sync& completer) {
if (!parent_.ReadyForAllocation()) {
parent_.FailSync(FROM_HERE, ConnectionVersion::kVersion2, completer, ZX_ERR_BAD_STATE,
"Release() before AllChildrenPresent()");
return;
}
parent_.ReleaseImpl(ConnectionVersion::kVersion2, completer);
}
void BufferCollectionTokenGroup::V1::GetNodeRef(GetNodeRefCompleter::Sync& completer) {
parent_.GetNodeRefImplV1(completer);
}
void BufferCollectionTokenGroup::V2::GetNodeRef(GetNodeRefCompleter::Sync& completer) {
parent_.GetNodeRefImplV2(completer);
}
void BufferCollectionTokenGroup::V1::IsAlternateFor(IsAlternateForRequest& request,
IsAlternateForCompleter::Sync& completer) {
parent_.IsAlternateForImplV1(request, completer);
}
void BufferCollectionTokenGroup::V2::IsAlternateFor(IsAlternateForRequest& request,
IsAlternateForCompleter::Sync& completer) {
parent_.IsAlternateForImplV2(request, completer);
}
void BufferCollectionTokenGroup::V2::GetBufferCollectionId(
GetBufferCollectionIdCompleter::Sync& completer) {
parent_.GetBufferCollectionIdImplV2(completer);
}
void BufferCollectionTokenGroup::V2::SetWeak(SetWeakCompleter::Sync& completer) {
parent_.SetWeakImplV2(completer);
}
void BufferCollectionTokenGroup::V2::SetWeakOk(SetWeakOkRequest& request,
SetWeakOkCompleter::Sync& completer) {
parent_.SetWeakOkImplV2(request, completer);
}
void BufferCollectionTokenGroup::V1::SetName(SetNameRequest& request,
SetNameCompleter::Sync& completer) {
parent_.SetNameImplV1(request, completer);
}
void BufferCollectionTokenGroup::V2::SetName(SetNameRequest& request,
SetNameCompleter::Sync& completer) {
parent_.SetNameImplV2(request, completer);
}
void BufferCollectionTokenGroup::V1::SetDebugClientInfo(
SetDebugClientInfoRequest& request, SetDebugClientInfoCompleter::Sync& completer) {
parent_.SetDebugClientInfoImplV1(request, completer);
}
void BufferCollectionTokenGroup::V2::SetDebugClientInfo(
SetDebugClientInfoRequest& request, SetDebugClientInfoCompleter::Sync& completer) {
parent_.SetDebugClientInfoImplV2(request, completer);
}
void BufferCollectionTokenGroup::V1::SetDebugTimeoutLogDeadline(
SetDebugTimeoutLogDeadlineRequest& request,
SetDebugTimeoutLogDeadlineCompleter::Sync& completer) {
parent_.SetDebugTimeoutLogDeadlineImplV1(request, completer);
}
void BufferCollectionTokenGroup::V2::SetDebugTimeoutLogDeadline(
SetDebugTimeoutLogDeadlineRequest& request,
SetDebugTimeoutLogDeadlineCompleter::Sync& completer) {
parent_.SetDebugTimeoutLogDeadlineImplV2(request, completer);
}
void BufferCollectionTokenGroup::V1::SetVerboseLogging(
SetVerboseLoggingCompleter::Sync& completer) {
parent_.SetVerboseLoggingImpl(ConnectionVersion::kVersion1, completer);
}
void BufferCollectionTokenGroup::V2::SetVerboseLogging(
SetVerboseLoggingCompleter::Sync& completer) {
parent_.SetVerboseLoggingImpl(ConnectionVersion::kVersion2, completer);
}
template <typename Completer>
bool BufferCollectionTokenGroup::CommonCreateChildStage1(
ConnectionVersion version, Completer& completer,
std::optional<uint32_t> input_rights_attenuation_mask, NodeProperties** out_node_properties) {
if (is_done_) {
FailSync(FROM_HERE, version, completer, ZX_ERR_BAD_STATE, "CreateChild() after Close()");
return false;
}
if (is_all_children_present_) {
FailSync(FROM_HERE, version, completer, ZX_ERR_BAD_STATE,
"CreateChild() after AllChildrenPresent()");
return false;
}
uint32_t rights_attenuation_mask = ZX_RIGHT_SAME_RIGHTS;
if (input_rights_attenuation_mask.has_value()) {
rights_attenuation_mask = input_rights_attenuation_mask.value();
}
if (rights_attenuation_mask == 0) {
FailSync(FROM_HERE, version, completer, ZX_ERR_INVALID_ARGS,
"CreateChild() rights_attenuation_mask 0 not permitted");
return false;
}
NodeProperties* new_node_properties = node_properties().NewChild(&logical_buffer_collection());
if (rights_attenuation_mask != ZX_RIGHT_SAME_RIGHTS) {
new_node_properties->rights_attenuation_mask() &= rights_attenuation_mask;
}
*out_node_properties = new_node_properties;
return true;
}
void BufferCollectionTokenGroup::V1::CreateChild(CreateChildRequest& request,
CreateChildCompleter::Sync& completer) {
if (!request.token_request().has_value()) {
parent_.FailSync(FROM_HERE, ConnectionVersion::kVersion1, completer, ZX_ERR_INVALID_ARGS,
"CreateChild() requires token_request set");
return;
}
std::optional<uint32_t> rights_attenuation_mask;
if (request.rights_attenuation_mask().has_value()) {
rights_attenuation_mask = request.rights_attenuation_mask().value();
}
NodeProperties* new_node_properties;
if (!parent_.CommonCreateChildStage1(ConnectionVersion::kVersion1, completer,
rights_attenuation_mask, &new_node_properties)) {
return;
}
parent_.logical_buffer_collection().CreateBufferCollectionTokenV1(
parent_.shared_logical_buffer_collection(), new_node_properties,
std::move(request.token_request().value()));
}
void BufferCollectionTokenGroup::V2::CreateChild(CreateChildRequest& request,
CreateChildCompleter::Sync& completer) {
if (!request.token_request().has_value()) {
parent_.FailSync(FROM_HERE, ConnectionVersion::kVersion2, completer, ZX_ERR_INVALID_ARGS,
"CreateChild() requires token_request set");
return;
}
// In contrast to CreateChildrenSync(), and in contrast to BufferCollectionToken::Duplicate(), we
// don't require rights_attenuation_mask to be set, since a BufferCollectionTokenGroup is often
// not the ideal place to impose a rights_attenuation_mask in the first place, so don't force the
// client to fill out a field that would very often just be ZX_RIGHT_SAME_RIGHTS anyway.
std::optional<uint32_t> rights_attenuation_mask;
if (request.rights_attenuation_mask().has_value()) {
rights_attenuation_mask = request.rights_attenuation_mask().value();
}
NodeProperties* new_node_properties;
if (!parent_.CommonCreateChildStage1(ConnectionVersion::kVersion2, completer,
rights_attenuation_mask, &new_node_properties)) {
return;
}
parent_.logical_buffer_collection().CreateBufferCollectionTokenV2(
parent_.shared_logical_buffer_collection(), new_node_properties,
std::move(request.token_request().value()));
}
void BufferCollectionTokenGroup::V1::CreateChildrenSync(
CreateChildrenSyncRequest& request, CreateChildrenSyncCompleter::Sync& completer) {
if (parent_.is_done_) {
parent_.FailSync(FROM_HERE, ConnectionVersion::kVersion1, completer, ZX_ERR_BAD_STATE,
"CreateChildrenSync() after Close()");
return;
}
if (parent_.is_all_children_present_) {
parent_.FailSync(FROM_HERE, ConnectionVersion::kVersion1, completer, ZX_ERR_BAD_STATE,
"CreateChildrenSync() after AllChildrenPresent()");
return;
}
for (auto& rights_attenuation_mask : request.rights_attenuation_masks()) {
if (rights_attenuation_mask == 0) {
parent_.FailSync(FROM_HERE, ConnectionVersion::kVersion1, completer, ZX_ERR_INVALID_ARGS,
"CreateChildrenSync() rights_attenuation_mask 0 not permitted");
return;
}
}
std::vector<fidl::ClientEnd<fuchsia_sysmem::BufferCollectionToken>> new_tokens;
for (auto& rights_attenuation_mask : request.rights_attenuation_masks()) {
auto token_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
if (!token_endpoints.is_ok()) {
parent_.FailSync(
FROM_HERE, ConnectionVersion::kVersion1, completer, token_endpoints.status_value(),
"BufferCollectionTokenGroup::CreateChildrenSync() failed to create token channel.");
return;
}
NodeProperties* new_node_properties =
parent_.node_properties().NewChild(&parent_.logical_buffer_collection());
if (rights_attenuation_mask != ZX_RIGHT_SAME_RIGHTS) {
new_node_properties->rights_attenuation_mask() &= rights_attenuation_mask;
}
parent_.logical_buffer_collection().CreateBufferCollectionTokenV1(
parent_.shared_logical_buffer_collection(), new_node_properties,
std::move(token_endpoints->server));
new_tokens.push_back(std::move(token_endpoints->client));
}
completer.Reply(std::move(new_tokens));
}
void BufferCollectionTokenGroup::V2::CreateChildrenSync(
CreateChildrenSyncRequest& request, CreateChildrenSyncCompleter::Sync& completer) {
if (parent_.is_done_) {
parent_.FailSync(FROM_HERE, ConnectionVersion::kVersion2, completer, ZX_ERR_BAD_STATE,
"CreateChildrenSync() after Close()");
return;
}
if (parent_.is_all_children_present_) {
parent_.FailSync(FROM_HERE, ConnectionVersion::kVersion2, completer, ZX_ERR_BAD_STATE,
"CreateChildrenSync() after AllChildrenPresent()");
return;
}
if (!request.rights_attenuation_masks().has_value()) {
// The size of rights_attenuation_mask determines how many children get created, so we need this
// set, despite it sometimes requiring the client to send a few ZX_RIGHT_SAME_RIGHTS, just to
// get the right number of children created (such as when the client is attenuating rights via
// a separate Duplicate() / DuplicateSync()).
parent_.FailSync(FROM_HERE, ConnectionVersion::kVersion2, completer, ZX_ERR_BAD_STATE,
"CreateChildrenSync() requires rights_attenuation_masks set");
return;
}
for (auto& rights_attenuation_mask : *request.rights_attenuation_masks()) {
if (rights_attenuation_mask == 0) {
parent_.FailSync(FROM_HERE, ConnectionVersion::kVersion2, completer, ZX_ERR_INVALID_ARGS,
"CreateChildrenSync() rights_attenuation_mask 0 not permitted");
return;
}
}
std::vector<fidl::ClientEnd<fuchsia_sysmem2::BufferCollectionToken>> new_tokens;
for (auto& rights_attenuation_mask : request.rights_attenuation_masks().value()) {
auto token_endpoints = fidl::CreateEndpoints<fuchsia_sysmem2::BufferCollectionToken>();
if (!token_endpoints.is_ok()) {
parent_.FailSync(
FROM_HERE, ConnectionVersion::kVersion2, completer, token_endpoints.status_value(),
"BufferCollectionTokenGroup::CreateChildrenSync() failed to create token channel.");
return;
}
NodeProperties* new_node_properties =
parent_.node_properties().NewChild(&parent_.logical_buffer_collection());
if (rights_attenuation_mask != ZX_RIGHT_SAME_RIGHTS) {
new_node_properties->rights_attenuation_mask() &= rights_attenuation_mask;
}
parent_.logical_buffer_collection().CreateBufferCollectionTokenV2(
parent_.shared_logical_buffer_collection(), new_node_properties,
std::move(token_endpoints->server));
new_tokens.push_back(std::move(token_endpoints->client));
}
fuchsia_sysmem2::BufferCollectionTokenGroupCreateChildrenSyncResponse response;
response.tokens().emplace(std::move(new_tokens));
completer.Reply(std::move(response));
}
template <typename Completer>
void BufferCollectionTokenGroup::CommonAllChildrenPresent(ConnectionVersion version,
Completer& completer) {
if (is_done_) {
FailSync(FROM_HERE, version, completer, ZX_ERR_BAD_STATE, "AllChildrenPresent() after Close()");
return;
}
if (is_all_children_present_) {
FailSync(FROM_HERE, version, completer, ZX_ERR_BAD_STATE,
"AllChildrenPresent() after AllChildrenPresent()");
return;
}
if (node_properties().child_count() < 1) {
// If this restriction creates a hassle, we could add a non-default per-group bool to allow zero
// children under a group if a client indicates that it may happen for a specific group. For now
// a client can add a child that sets empty constraints, if it turns out after creating a group
// that the group won't need to have any children.
FailSync(FROM_HERE, version, completer, ZX_ERR_BAD_STATE,
"AllChildrenPresent() without any children");
return;
}
is_all_children_present_ = true;
logical_buffer_collection().OnDependencyReady();
}
void BufferCollectionTokenGroup::V1::AllChildrenPresent(
AllChildrenPresentCompleter::Sync& completer) {
parent_.CommonAllChildrenPresent(ConnectionVersion::kVersion1, completer);
}
void BufferCollectionTokenGroup::V2::AllChildrenPresent(
AllChildrenPresentCompleter::Sync& completer) {
parent_.CommonAllChildrenPresent(ConnectionVersion::kVersion2, completer);
}
void BufferCollectionTokenGroup::V2::handle_unknown_method(
fidl::UnknownMethodMetadata<fuchsia_sysmem2::BufferCollectionTokenGroup> metadata,
fidl::UnknownMethodCompleter::Sync& completer) {
parent_.FailSync(FROM_HERE, ConnectionVersion::kVersion2, completer, ZX_ERR_NOT_SUPPORTED,
"token group unknown method - ordinal: %" PRIx64, metadata.method_ordinal);
}
BufferCollectionTokenGroup& BufferCollectionTokenGroup::EmplaceInTree(
fbl::RefPtr<LogicalBufferCollection> logical_buffer_collection,
NodeProperties* new_node_properties, const GroupServerEnd& server_end) {
auto group = fbl::AdoptRef(new BufferCollectionTokenGroup(
std::move(logical_buffer_collection), new_node_properties, std::move(server_end)));
auto group_ptr = group.get();
new_node_properties->SetNode(group);
return *group_ptr;
}
BufferCollectionTokenGroup::BufferCollectionTokenGroup(fbl::RefPtr<LogicalBufferCollection> parent,
NodeProperties* new_node_properties,
const GroupServerEnd& server_end)
: Node(std::move(parent), new_node_properties, GetUnownedChannel(server_end)) {
TRACE_DURATION("gfx", "BufferCollectionTokenGroup::BufferCollectionTokenGroup", "this", this,
"logical_buffer_collection", &this->logical_buffer_collection());
ZX_DEBUG_ASSERT(shared_logical_buffer_collection());
inspect_node_ =
this->logical_buffer_collection().inspect_node().CreateChild(CreateUniqueName("group-"));
}
void BufferCollectionTokenGroup::Bind(GroupServerEnd server_end) {
Node::Bind(TakeNodeServerEnd(std::move(server_end)));
}
void BufferCollectionTokenGroup::BindInternalV1(zx::channel group_request,
ErrorHandlerWrapper error_handler_wrapper) {
v1_server_.emplace(*this);
server_binding_v1_ = fidl::BindServer(
parent_device()->dispatcher(),
fidl::ServerEnd<fuchsia_sysmem::BufferCollectionTokenGroup>(std::move(group_request)),
&v1_server_.value(),
[error_handler_wrapper = std::move(error_handler_wrapper)](
BufferCollectionTokenGroup::V1* group, fidl::UnbindInfo info, GroupServerEndV1 channel) {
error_handler_wrapper(info);
});
}
void BufferCollectionTokenGroup::BindInternalV2(zx::channel group_request,
ErrorHandlerWrapper error_handler_wrapper) {
v2_server_.emplace(*this);
server_binding_v2_ = fidl::BindServer(
parent_device()->dispatcher(),
fidl::ServerEnd<fuchsia_sysmem2::BufferCollectionTokenGroup>(std::move(group_request)),
&v2_server_.value(),
[error_handler_wrapper = std::move(error_handler_wrapper)](
BufferCollectionTokenGroup::V2* group, fidl::UnbindInfo info, GroupServerEndV2 channel) {
error_handler_wrapper(info);
});
}
void BufferCollectionTokenGroup::BindInternalCombinedV1AndV2(
zx::channel server_end, ErrorHandlerWrapper error_handler_wrapper) {
ZX_PANIC("BufferCollectionTokenGroup only serves V1 or V2 separately - never combined V1 and V2");
}
bool BufferCollectionTokenGroup::ReadyForAllocation() { return is_all_children_present_; }
void BufferCollectionTokenGroup::OnBuffersAllocated(const AllocationResult& allocation_result) {
node_properties().SetBuffersLogicallyAllocated();
}
BufferCollectionToken* BufferCollectionTokenGroup::buffer_collection_token() { return nullptr; }
const BufferCollectionToken* BufferCollectionTokenGroup::buffer_collection_token() const {
return nullptr;
}
BufferCollection* BufferCollectionTokenGroup::buffer_collection() { return nullptr; }
const BufferCollection* BufferCollectionTokenGroup::buffer_collection() const { return nullptr; }
OrphanedNode* BufferCollectionTokenGroup::orphaned_node() { return nullptr; }
const OrphanedNode* BufferCollectionTokenGroup::orphaned_node() const { return nullptr; }
BufferCollectionTokenGroup* BufferCollectionTokenGroup::buffer_collection_token_group() {
return this;
}
const BufferCollectionTokenGroup* BufferCollectionTokenGroup::buffer_collection_token_group()
const {
return this;
}
bool BufferCollectionTokenGroup::is_connected_type() const { return true; }
bool BufferCollectionTokenGroup::is_currently_connected() const {
return server_binding_v1_.has_value() || server_binding_v2_.has_value();
}
void BufferCollectionTokenGroup::CloseServerBinding(zx_status_t epitaph) {
if (server_binding_v1_.has_value()) {
server_binding_v1_->Close(epitaph);
}
if (server_binding_v2_.has_value()) {
server_binding_v2_->Close(ZX_ERR_INTERNAL);
}
server_binding_v1_ = {};
server_binding_v2_ = {};
}
const char* BufferCollectionTokenGroup::node_type_string() const { return "group"; }
ConnectionVersion BufferCollectionTokenGroup::connection_version() const {
if (server_binding_v2_.has_value()) {
return ConnectionVersion::kVersion2;
}
if (server_binding_v1_.has_value()) {
return ConnectionVersion::kVersion1;
}
return ConnectionVersion::kNoConnection;
}
} // namespace sysmem_driver