// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/display/manager/query_content_protection_task.h"
#include <utility>
#include "base/functional/bind.h"
#include "ui/display/manager/display_layout_manager.h"
#include "ui/display/manager/util/display_manager_util.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/display/types/native_display_delegate.h"
namespace display {
QueryContentProtectionTask::QueryContentProtectionTask(
DisplayLayoutManager* layout_manager,
NativeDisplayDelegate* native_display_delegate,
int64_t display_id,
ResponseCallback callback)
: layout_manager_(layout_manager),
native_display_delegate_(native_display_delegate),
display_id_(display_id),
callback_(std::move(callback)) {}
QueryContentProtectionTask::~QueryContentProtectionTask() {
if (callback_) {
std::move(callback_).Run(Status::KILLED, DISPLAY_CONNECTION_TYPE_NONE,
CONTENT_PROTECTION_METHOD_NONE);
}
}
void QueryContentProtectionTask::Run() {
std::vector<DisplaySnapshot*> hdcp_capable_displays;
for (DisplaySnapshot* display : layout_manager_->GetDisplayStates()) {
// Query all displays in mirroring mode. Otherwise, query the given display,
// which must exist because tasks are killed on display reconfiguration.
if (!layout_manager_->IsMirroring() && display->display_id() != display_id_)
continue;
connection_mask_ |= display->type();
uint32_t protection_mask;
if (!GetContentProtectionMethods(display->type(), &protection_mask)) {
std::move(callback_).Run(Status::FAILURE, DISPLAY_CONNECTION_TYPE_UNKNOWN,
CONTENT_PROTECTION_METHOD_NONE);
return;
}
// Collect displays to be queried based on HDCP capability. For unprotected
// displays not inherently secure through an internal connection, record the
// existence of an unsecure display to report no protection for all displays
// in mirroring mode.
if (protection_mask & kContentProtectionMethodHdcpAll)
hdcp_capable_displays.push_back(display);
else if (display->type() != DISPLAY_CONNECTION_TYPE_INTERNAL)
no_protection_mask_ |= kContentProtectionMethodHdcpAll;
}
pending_requests_ = hdcp_capable_displays.size();
if (pending_requests_ == 0) {
std::move(callback_).Run(Status::SUCCESS, connection_mask_,
CONTENT_PROTECTION_METHOD_NONE);
return;
}
for (DisplaySnapshot* display : hdcp_capable_displays) {
native_display_delegate_->GetHDCPState(
*display, base::BindOnce(&QueryContentProtectionTask::OnGetHDCPState,
weak_ptr_factory_.GetWeakPtr()));
}
}
void QueryContentProtectionTask::OnGetHDCPState(
bool success,
HDCPState state,
ContentProtectionMethod protection_method) {
success_ &= success;
if (state == HDCP_STATE_ENABLED)
protection_mask_ |= protection_method;
else
no_protection_mask_ |= kContentProtectionMethodHdcpAll;
pending_requests_--;
// Wait for all the requests to finish before invoking the callback.
if (pending_requests_ != 0)
return;
protection_mask_ &= ~no_protection_mask_;
// If HDCP Type 1 and Type 0 are in the protection mask, then remove Type 1
// from the mask since we want to reflect the overall output security. If only
// Type 1 is in the protection mask, then also add Type 0 to the mask so we
// properly support clients that were written before Type 1 was added.
if ((protection_mask_ & kContentProtectionMethodHdcpAll) ==
kContentProtectionMethodHdcpAll) {
protection_mask_ &= ~CONTENT_PROTECTION_METHOD_HDCP_TYPE_1;
} else if (protection_mask_ & CONTENT_PROTECTION_METHOD_HDCP_TYPE_1) {
protection_mask_ |= CONTENT_PROTECTION_METHOD_HDCP_TYPE_0;
}
std::move(callback_).Run(success_ ? Status::SUCCESS : Status::FAILURE,
connection_mask_, protection_mask_);
}
} // namespace display