blob: 7020f2796b112216bc252039e28589644eac9cc1 [file] [log] [blame]
// Copyright 2020 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 "src/graphics/drivers/misc/goldfish_control/control_device.h"
#include <fidl/fuchsia.hardware.goldfish.pipe/cpp/markers.h>
#include <fidl/fuchsia.hardware.goldfish.pipe/cpp/wire.h>
#include <fidl/fuchsia.hardware.goldfish/cpp/wire_test_base.h>
#include <fidl/fuchsia.hardware.sysmem/cpp/wire.h>
#include <fidl/fuchsia.hardware.sysmem/cpp/wire_test_base.h>
#include <fidl/fuchsia.sysmem2/cpp/wire.h>
#include <fidl/fuchsia.sysmem2/cpp/wire_test_base.h>
#include <fuchsia/hardware/goldfish/control/cpp/banjo.h>
#include <lib/async-loop/loop.h>
#include <lib/async-loop/testing/cpp/real_loop.h>
#include <lib/component/outgoing/cpp/outgoing_directory.h>
#include <lib/fake-bti/bti.h>
#include <lib/fidl/cpp/wire/connect_service.h>
#include <lib/fzl/vmo-mapper.h>
#include <lib/zx/bti.h>
#include <lib/zx/vmar.h>
#include <lib/zx/vmo.h>
#include <zircon/errors.h>
#include <zircon/rights.h>
#include <cstdlib>
#include <memory>
#include <string>
#include <unordered_map>
#include <fbl/array.h>
#include <fbl/auto_lock.h>
#include <gtest/gtest.h>
#include "src/devices/lib/goldfish/pipe_headers/include/base.h"
#include "src/devices/testing/mock-ddk/mock-device.h"
#include "src/graphics/drivers/misc/goldfish_control/render_control_commands.h"
#include "src/lib/fsl/handles/object_info.h"
#define ASSERT_OK(expr) ASSERT_EQ(ZX_OK, expr)
#define EXPECT_OK(expr) EXPECT_EQ(ZX_OK, expr)
namespace goldfish {
namespace {
// TODO(https://fxbug.dev/42161009): Use //src/devices/lib/goldfish/fake_pipe instead.
class FakePipe : public fidl::WireServer<fuchsia_hardware_goldfish_pipe::GoldfishPipe> {
public:
struct HeapInfo {
fidl::ClientEnd<fuchsia_hardware_sysmem::Heap> heap_client_end;
bool is_registered = false;
bool cpu_supported = false;
bool ram_supported = false;
bool inaccessible_supported = false;
};
void Create(CreateCompleter::Sync& completer) override {
zx::vmo vmo;
zx_status_t status = zx::vmo::create(PAGE_SIZE, 0u, &vmo);
if (status != ZX_OK) {
completer.Close(status);
return;
}
status = vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &pipe_cmd_buffer_);
if (status != ZX_OK) {
completer.Close(status);
return;
}
pipe_created_ = true;
completer.ReplySuccess(kPipeId, std::move(vmo));
}
void SetEvent(SetEventRequestView request, SetEventCompleter::Sync& completer) override {
if (request->id != kPipeId) {
completer.Close(ZX_ERR_INVALID_ARGS);
return;
}
if (!request->pipe_event.is_valid()) {
completer.Close(ZX_ERR_BAD_HANDLE);
return;
}
pipe_event_ = std::move(request->pipe_event);
completer.ReplySuccess();
}
void Destroy(DestroyRequestView request, DestroyCompleter::Sync& completer) override {
pipe_cmd_buffer_.reset();
completer.Reply();
}
void Open(OpenRequestView request, OpenCompleter::Sync& completer) override {
auto mapping = MapCmdBuffer();
reinterpret_cast<PipeCmdBuffer*>(mapping.start())->status = 0;
pipe_opened_ = true;
completer.Reply();
}
void Exec(ExecRequestView request, ExecCompleter::Sync& completer) override {
auto mapping = MapCmdBuffer();
PipeCmdBuffer* cmd_buffer = reinterpret_cast<PipeCmdBuffer*>(mapping.start());
cmd_buffer->rw_params.consumed_size = cmd_buffer->rw_params.sizes[0];
cmd_buffer->status = 0;
if (cmd_buffer->cmd ==
static_cast<int32_t>(fuchsia_hardware_goldfish_pipe::PipeCmdCode::kWrite)) {
// Store io buffer contents.
auto io_buffer = MapIoBuffer();
io_buffer_contents_.emplace_back(std::vector<uint8_t>(io_buffer_size_, 0));
memcpy(io_buffer_contents_.back().data(), io_buffer.start(), io_buffer_size_);
}
if (cmd_buffer->cmd ==
static_cast<int32_t>(fuchsia_hardware_goldfish_pipe::PipeCmdCode::kRead)) {
auto io_buffer = MapIoBuffer();
uint32_t op = *reinterpret_cast<uint32_t*>(io_buffer.start());
switch (op) {
case kOP_rcCreateBuffer2:
case kOP_rcCreateColorBuffer:
*reinterpret_cast<uint32_t*>(io_buffer.start()) = ++buffer_id_;
break;
case kOP_rcMapGpaToBufferHandle2:
case kOP_rcSetColorBufferVulkanMode2:
*reinterpret_cast<int32_t*>(io_buffer.start()) = 0;
break;
default:
ZX_ASSERT_MSG(false, "invalid renderControl command (op %u)", op);
}
}
completer.Reply();
}
void GetBti(GetBtiCompleter::Sync& completer) override {
zx::bti bti;
zx_status_t status = fake_bti_create(bti.reset_and_get_address());
if (status != ZX_OK) {
completer.Close(status);
return;
}
bti_ = bti.borrow();
completer.ReplySuccess(std::move(bti));
}
void ConnectSysmem(ConnectSysmemRequestView request,
ConnectSysmemCompleter::Sync& completer) override {
completer.ReplySuccess();
}
void RegisterSysmemHeap(RegisterSysmemHeapRequestView request,
RegisterSysmemHeapCompleter::Sync& completer) override {
heap_info_[request->heap] = {};
heap_info_[request->heap].heap_client_end =
fidl::ClientEnd<fuchsia_hardware_sysmem::Heap>(std::move(request->connection));
completer.ReplySuccess();
}
zx_status_t SetUpPipeDevice() {
zx_status_t status = HandleSysmemEvents();
if (status != ZX_OK) {
return status;
}
if (!pipe_io_buffer_.is_valid()) {
status = PrepareIoBuffer();
if (status != ZX_OK) {
return status;
}
}
return ZX_OK;
}
fzl::VmoMapper MapCmdBuffer() const {
fzl::VmoMapper mapping;
mapping.Map(pipe_cmd_buffer_, 0, sizeof(PipeCmdBuffer), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE);
return mapping;
}
fzl::VmoMapper MapIoBuffer() {
if (!pipe_io_buffer_.is_valid()) {
PrepareIoBuffer();
}
fzl::VmoMapper mapping;
mapping.Map(pipe_io_buffer_, 0, io_buffer_size_, ZX_VM_PERM_READ | ZX_VM_PERM_WRITE);
return mapping;
}
bool IsPipeReady() const { return pipe_created_ && pipe_opened_; }
uint32_t CurrentBufferHandle() { return buffer_id_; }
const std::unordered_map<uint64_t, HeapInfo>& heap_info() const { return heap_info_; }
const std::vector<std::vector<uint8_t>>& io_buffer_contents() const {
return io_buffer_contents_;
}
private:
class SysmemHeapEventHandler : public fidl::WireSyncEventHandler<fuchsia_hardware_sysmem::Heap> {
public:
SysmemHeapEventHandler() = default;
void OnRegister(fidl::WireEvent<fuchsia_hardware_sysmem::Heap::OnRegister>* message) override {
if (handler != nullptr) {
handler(message);
}
}
void SetOnRegisterHandler(
fit::function<void(fidl::WireEvent<fuchsia_hardware_sysmem::Heap::OnRegister>*)>
new_handler) {
handler = std::move(new_handler);
}
private:
fit::function<void(fidl::WireEvent<fuchsia_hardware_sysmem::Heap::OnRegister>*)> handler;
};
zx_status_t HandleSysmemEvents() {
zx_status_t status = ZX_OK;
for (auto& kv : heap_info_) {
SysmemHeapEventHandler handler;
handler.SetOnRegisterHandler(
[this,
heap = kv.first](fidl::WireEvent<fuchsia_hardware_sysmem::Heap::OnRegister>* message) {
auto& heap_info = heap_info_[heap];
heap_info.is_registered = true;
heap_info.cpu_supported =
message->properties.coherency_domain_support().cpu_supported();
heap_info.ram_supported =
message->properties.coherency_domain_support().ram_supported();
heap_info.inaccessible_supported =
message->properties.coherency_domain_support().inaccessible_supported();
});
status = handler.HandleOneEvent(kv.second.heap_client_end).status();
if (status != ZX_OK) {
break;
}
}
return status;
}
zx_status_t PrepareIoBuffer() {
uint64_t num_pinned_vmos = 0u;
std::vector<fake_bti_pinned_vmo_info_t> pinned_vmos;
zx_status_t status = fake_bti_get_pinned_vmos(bti_->get(), nullptr, 0, &num_pinned_vmos);
if (status != ZX_OK) {
return status;
}
if (num_pinned_vmos == 0u) {
return ZX_ERR_NOT_FOUND;
}
pinned_vmos.resize(num_pinned_vmos);
status = fake_bti_get_pinned_vmos(bti_->get(), pinned_vmos.data(), num_pinned_vmos, nullptr);
if (status != ZX_OK) {
return status;
}
pipe_io_buffer_ = zx::vmo(pinned_vmos.back().vmo);
pinned_vmos.pop_back();
// close all the unused handles
for (auto vmo_info : pinned_vmos) {
zx_handle_close(vmo_info.vmo);
}
status = pipe_io_buffer_.get_size(&io_buffer_size_);
return status;
}
zx::unowned_bti bti_;
static constexpr int32_t kPipeId = 1;
zx::vmo pipe_cmd_buffer_ = zx::vmo();
zx::vmo pipe_io_buffer_ = zx::vmo();
size_t io_buffer_size_;
zx::event pipe_event_;
bool pipe_created_ = false;
bool pipe_opened_ = false;
int32_t buffer_id_ = 0;
std::unordered_map<uint64_t, HeapInfo> heap_info_;
std::vector<std::vector<uint8_t>> io_buffer_contents_;
};
class FakeAddressSpace : public fidl::WireServer<fuchsia_hardware_goldfish::AddressSpaceDevice> {
void OpenChildDriver(OpenChildDriverRequestView request,
OpenChildDriverCompleter::Sync& completer) override {
request->req.Close(ZX_ERR_NOT_SUPPORTED);
completer.Close(ZX_ERR_NOT_SUPPORTED);
}
};
class FakeAddressSpaceChild
: public fidl::testing::WireTestBase<fuchsia_hardware_goldfish::AddressSpaceChildDriver> {
void NotImplemented_(const std::string& name, fidl::CompleterBase& completer) override {
ADD_FAILURE() << "unexpected call to " << name;
completer.Close(ZX_ERR_NOT_SUPPORTED);
}
};
class FakeSync : public fidl::WireServer<fuchsia_hardware_goldfish::SyncDevice> {
public:
void CreateTimeline(CreateTimelineRequestView request,
CreateTimelineCompleter::Sync& completer) override {
completer.Reply();
}
};
class FakeHardwareSysmem;
class FakeSysmemAllocator : public fidl::testing::WireTestBase<fuchsia_sysmem2::Allocator> {
public:
FakeSysmemAllocator(FakeHardwareSysmem& parent) : parent_(parent) {}
virtual void GetVmoInfo(::fuchsia_sysmem2::wire::AllocatorGetVmoInfoRequest* request,
GetVmoInfoCompleter::Sync& completer) override;
void NotImplemented_(const std::string& name, ::fidl::CompleterBase& completer) override {
ADD_FAILURE() << "unexpected call to " << name;
completer.Close(ZX_ERR_NOT_SUPPORTED);
}
private:
FakeHardwareSysmem& parent_;
};
class FakeHardwareSysmem : public fidl::testing::WireTestBase<fuchsia_hardware_sysmem::Sysmem> {
public:
void AddFakeVmoInfo(const zx::vmo& vmo, BufferKey buffer_key) {
zx_koid_t koid = fsl::GetKoid(vmo.get());
ZX_ASSERT(koid != ZX_KOID_INVALID);
auto emplace_result = vmo_infos_.try_emplace(koid, buffer_key);
ZX_ASSERT(emplace_result.second);
}
std::optional<BufferKey> LookupFakeVmoInfo(const zx::vmo& vmo) {
zx_koid_t koid = fsl::GetKoid(vmo.get());
auto iter = vmo_infos_.find(koid);
if (iter == vmo_infos_.end()) {
return std::nullopt;
}
return iter->second;
}
void NotImplemented_(const std::string& name, ::fidl::CompleterBase& completer) override {
ADD_FAILURE() << "unexpected call to " << name;
completer.Close(ZX_ERR_NOT_SUPPORTED);
}
private:
using VmoInfoMap = std::unordered_map<zx_koid_t, BufferKey>;
VmoInfoMap vmo_infos_;
};
void FakeSysmemAllocator::GetVmoInfo(::fuchsia_sysmem2::wire::AllocatorGetVmoInfoRequest* request,
GetVmoInfoCompleter::Sync& completer) {
auto buffer_key = parent_.LookupFakeVmoInfo(request->vmo());
if (!buffer_key.has_value()) {
completer.ReplyError(fuchsia_sysmem2::Error::kNotFound);
return;
}
fidl::Arena arena;
auto response = fuchsia_sysmem2::wire::AllocatorGetVmoInfoResponse::Builder(arena);
response.buffer_collection_id(buffer_key->first);
response.buffer_index(buffer_key->second);
completer.ReplySuccess(response.Build());
}
class ControlDeviceTest : public testing::Test, public loop_fixture::RealLoop {
public:
ControlDeviceTest()
: loop_(&kAsyncLoopConfigNeverAttachToThread),
pipe_server_loop_(&kAsyncLoopConfigNeverAttachToThread),
address_space_server_loop_(&kAsyncLoopConfigNeverAttachToThread),
sync_server_loop_(&kAsyncLoopConfigNeverAttachToThread),
sysmem_server_loop_(&kAsyncLoopConfigNeverAttachToThread),
sysmem_(hardware_sysmem_),
outgoing_(dispatcher()) {}
void SetUp() override {
fake_parent_ = MockDevice::FakeRootParent();
zx::result service_result = outgoing_.AddService<fuchsia_hardware_goldfish_pipe::Service>(
fuchsia_hardware_goldfish_pipe::Service::InstanceHandler({
.device = pipe_.bind_handler(pipe_server_loop_.dispatcher()),
}));
ASSERT_EQ(service_result.status_value(), ZX_OK);
zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
ASSERT_OK(endpoints.status_value());
ASSERT_OK(outgoing_.Serve(std::move(endpoints->server)).status_value());
fake_parent_->AddFidlService(fuchsia_hardware_goldfish_pipe::Service::Name,
std::move(endpoints->client), "goldfish-pipe");
service_result = outgoing_.AddService<fuchsia_hardware_goldfish::AddressSpaceService>(
fuchsia_hardware_goldfish::AddressSpaceService::InstanceHandler({
.device = address_space_.bind_handler(address_space_server_loop_.dispatcher()),
}));
ASSERT_EQ(service_result.status_value(), ZX_OK);
endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
ASSERT_OK(endpoints.status_value());
ASSERT_OK(outgoing_.Serve(std::move(endpoints->server)).status_value());
fake_parent_->AddFidlService(fuchsia_hardware_goldfish::AddressSpaceService::Name,
std::move(endpoints->client), "goldfish-address-space");
service_result = outgoing_.AddService<fuchsia_hardware_goldfish::SyncService>(
fuchsia_hardware_goldfish::SyncService::InstanceHandler({
.device = sync_.bind_handler(sync_server_loop_.dispatcher()),
}));
ASSERT_EQ(service_result.status_value(), ZX_OK);
endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
ASSERT_OK(endpoints.status_value());
ASSERT_OK(outgoing_.Serve(std::move(endpoints->server)).status_value());
fake_parent_->AddFidlService(fuchsia_hardware_goldfish::SyncService::Name,
std::move(endpoints->client), "goldfish-sync");
service_result = outgoing_.AddService<fuchsia_hardware_sysmem::Service>(
fuchsia_hardware_sysmem::Service::InstanceHandler({
.sysmem = hardware_sysmem_.bind_handler(sysmem_server_loop_.dispatcher()),
// specifically not filling out allocator_v1 since that's not what the driver uses
// (currently).
.allocator_v2 = sysmem_.bind_handler(sysmem_server_loop_.dispatcher()),
}));
ASSERT_EQ(service_result.status_value(), ZX_OK);
endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
ASSERT_OK(endpoints.status_value());
ASSERT_OK(outgoing_.Serve(std::move(endpoints->server)).status_value());
fake_parent_->AddFidlService(fuchsia_hardware_sysmem::Service::Name,
std::move(endpoints->client), "sysmem");
pipe_server_loop_.StartThread("goldfish-pipe-fidl-server");
address_space_server_loop_.StartThread("goldfish-address-space-fidl-server");
sync_server_loop_.StartThread("goldfish-sync-fidl-server");
sysmem_server_loop_.StartThread("sysmem-fidl-server");
auto dut = std::make_unique<Control>(fake_parent_.get());
PerformBlockingWork([&]() { ASSERT_EQ(dut->Bind(), ZX_OK); });
// The device will be deleted by MockDevice when the test ends.
dut.release();
ASSERT_EQ(fake_parent_->child_count(), 1u);
auto fake_dut = fake_parent_->GetLatestChild();
dut_ = fake_dut->GetDeviceContext<Control>();
ASSERT_OK(pipe_.SetUpPipeDevice());
ASSERT_TRUE(pipe_.IsPipeReady());
// Bind control device FIDL server.
auto control_endpoints = fidl::CreateEndpoints<fuchsia_hardware_goldfish::ControlDevice>();
ASSERT_TRUE(control_endpoints.is_ok());
control_fidl_server_ =
fidl::BindServer(loop_.dispatcher(), std::move(control_endpoints->server),
fake_dut->GetDeviceContext<Control>());
loop_.StartThread("goldfish-control-device-fidl-server");
fidl_client_ = fidl::WireSyncClient(std::move(control_endpoints->client));
}
void TearDown() override {
device_async_remove(dut_->zxdev());
mock_ddk::ReleaseFlaggedDevices(fake_parent_.get());
}
protected:
Control* dut_ = nullptr;
async::Loop loop_;
async::Loop pipe_server_loop_;
async::Loop address_space_server_loop_;
async::Loop sync_server_loop_;
async::Loop sysmem_server_loop_;
FakePipe pipe_;
FakeAddressSpace address_space_;
FakeAddressSpaceChild address_space_child_;
FakeSync sync_;
FakeHardwareSysmem hardware_sysmem_;
FakeSysmemAllocator sysmem_;
std::shared_ptr<MockDevice> fake_parent_;
component::OutgoingDirectory outgoing_;
std::optional<fidl::ServerBindingRef<fuchsia_hardware_goldfish::ControlDevice>>
control_fidl_server_ = std::nullopt;
fidl::WireSyncClient<fuchsia_hardware_goldfish::ControlDevice> fidl_client_ = {};
};
TEST_F(ControlDeviceTest, Bind) {
const auto& heaps = pipe_.heap_info();
ASSERT_EQ(heaps.size(), 2u);
ASSERT_TRUE(heaps.find(static_cast<uint64_t>(
fuchsia_sysmem::wire::HeapType::kGoldfishDeviceLocal)) != heaps.end());
ASSERT_TRUE(heaps.find(static_cast<uint64_t>(
fuchsia_sysmem::wire::HeapType::kGoldfishHostVisible)) != heaps.end());
const auto& device_local_heap_info =
heaps.at(static_cast<uint64_t>(fuchsia_sysmem::wire::HeapType::kGoldfishDeviceLocal));
EXPECT_TRUE(device_local_heap_info.heap_client_end.is_valid());
EXPECT_TRUE(device_local_heap_info.is_registered);
EXPECT_TRUE(device_local_heap_info.inaccessible_supported);
const auto& host_visible_heap_info =
heaps.at(static_cast<uint64_t>(fuchsia_sysmem::wire::HeapType::kGoldfishHostVisible));
EXPECT_TRUE(host_visible_heap_info.heap_client_end.is_valid());
EXPECT_TRUE(host_visible_heap_info.is_registered);
EXPECT_TRUE(host_visible_heap_info.cpu_supported);
}
// Test |fuchsia.hardware.goldfish.Control.CreateBuffer2| method.
class BufferTest : public ControlDeviceTest, public testing::WithParamInterface<uint32_t> {};
TEST_P(BufferTest, TestCreate2) {
constexpr size_t kSize = 65536u;
constexpr uint64_t kPhysicalAddress = 0x12345678abcd0000;
const auto memory_property = GetParam();
const bool is_host_visible =
memory_property == fuchsia_hardware_goldfish::wire::kMemoryPropertyHostVisible;
const BufferKey buffer_key(12, 0);
zx::vmo buffer_vmo;
ASSERT_OK(zx::vmo::create(kSize, 0u, &buffer_vmo));
hardware_sysmem_.AddFakeVmoInfo(buffer_vmo, buffer_key);
dut_->RegisterBufferHandle(buffer_key);
fidl::Arena allocator;
fuchsia_hardware_goldfish::wire::CreateBuffer2Params create_params(allocator);
create_params.set_size(allocator, kSize).set_memory_property(memory_property);
if (is_host_visible) {
create_params.set_physical_address(allocator, kPhysicalAddress);
}
auto create_buffer_result =
fidl_client_->CreateBuffer2(std::move(buffer_vmo), std::move(create_params));
ASSERT_TRUE(create_buffer_result.ok());
ASSERT_TRUE(create_buffer_result->is_ok());
CreateBuffer2Cmd create_buffer_cmd{
.op = kOP_rcCreateBuffer2,
.size = kSize_rcCreateBuffer2,
.buffer_size = kSize,
.memory_property = memory_property,
};
MapGpaToBufferHandle2Cmd map_gpa_cmd{
.op = kOP_rcMapGpaToBufferHandle2,
.size = kSize_rcMapGpaToBufferHandle2,
.id = pipe_.CurrentBufferHandle(),
.gpa = kPhysicalAddress,
.map_size = kSize,
};
const auto& io_buffer_contents = pipe_.io_buffer_contents();
size_t create_buffer_cmd_idx = 0;
if (is_host_visible) {
ASSERT_GE(io_buffer_contents.size(), 2u);
create_buffer_cmd_idx = io_buffer_contents.size() - 2;
} else {
ASSERT_GE(io_buffer_contents.size(), 1u);
create_buffer_cmd_idx = io_buffer_contents.size() - 1;
}
EXPECT_EQ(memcmp(&create_buffer_cmd, io_buffer_contents[create_buffer_cmd_idx].data(),
sizeof(CreateBuffer2Cmd)),
0);
if (is_host_visible) {
EXPECT_EQ(memcmp(&map_gpa_cmd, io_buffer_contents[create_buffer_cmd_idx + 1].data(),
sizeof(MapGpaToBufferHandle2Cmd)),
0);
}
}
INSTANTIATE_TEST_SUITE_P(
ControlDeviceTest, BufferTest,
testing::Values(fuchsia_hardware_goldfish::wire::kMemoryPropertyDeviceLocal,
fuchsia_hardware_goldfish::wire::kMemoryPropertyHostVisible),
[](const testing::TestParamInfo<BufferTest::ParamType>& info) {
std::string memory_property;
switch (info.param) {
case fuchsia_hardware_goldfish::wire::kMemoryPropertyDeviceLocal:
memory_property = "DEVICE_LOCAL";
break;
case fuchsia_hardware_goldfish::wire::kMemoryPropertyHostVisible:
memory_property = "HOST_VISIBLE";
break;
default:
memory_property = "UNSUPPORTED_MEMORY_PROPERTY";
}
return memory_property;
});
TEST_F(ControlDeviceTest, CreateBuffer2_AlreadyExists) {
constexpr size_t kSize = 65536u;
constexpr BufferKey buffer_key(12, 0);
zx::vmo buffer_vmo;
ASSERT_OK(zx::vmo::create(kSize, 0u, &buffer_vmo));
zx::vmo copy_vmo;
ASSERT_OK(buffer_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &copy_vmo));
hardware_sysmem_.AddFakeVmoInfo(buffer_vmo, buffer_key);
dut_->RegisterBufferHandle(buffer_key);
fidl::Arena allocator;
fuchsia_hardware_goldfish::wire::CreateBuffer2Params create_params(allocator);
create_params.set_size(allocator, kSize)
.set_memory_property(fuchsia_hardware_goldfish::wire::kMemoryPropertyDeviceLocal);
auto create_buffer_result =
fidl_client_->CreateBuffer2(std::move(buffer_vmo), std::move(create_params));
ASSERT_TRUE(create_buffer_result.ok());
ASSERT_TRUE(create_buffer_result->is_ok());
fuchsia_hardware_goldfish::wire::CreateBuffer2Params create_params2(allocator);
create_params2.set_size(allocator, kSize)
.set_memory_property(fuchsia_hardware_goldfish::wire::kMemoryPropertyDeviceLocal);
auto create_copy_buffer_result =
fidl_client_->CreateBuffer2(std::move(copy_vmo), std::move(create_params2));
ASSERT_TRUE(create_copy_buffer_result.ok());
ASSERT_TRUE(create_copy_buffer_result->is_error());
ASSERT_EQ(create_copy_buffer_result->error_value(), ZX_ERR_ALREADY_EXISTS);
}
TEST_F(ControlDeviceTest, CreateBuffer2_InvalidArgs) {
constexpr size_t kSize = 65536u;
{
const BufferKey buffer_key(12, 0);
zx::vmo buffer_vmo;
ASSERT_OK(zx::vmo::create(kSize, 0u, &buffer_vmo));
hardware_sysmem_.AddFakeVmoInfo(buffer_vmo, buffer_key);
dut_->RegisterBufferHandle(buffer_key);
fidl::Arena allocator;
fuchsia_hardware_goldfish::wire::CreateBuffer2Params create_params(allocator);
// missing size
create_params.set_memory_property(fuchsia_hardware_goldfish::wire::kMemoryPropertyDeviceLocal);
auto result = fidl_client_->CreateBuffer2(std::move(buffer_vmo), std::move(create_params));
ASSERT_TRUE(result.ok());
ASSERT_TRUE(result->is_error());
ASSERT_EQ(result->error_value(), ZX_ERR_INVALID_ARGS);
dut_->FreeBufferHandle(buffer_key);
}
{
const BufferKey buffer_key(13, 1);
zx::vmo buffer_vmo;
ASSERT_OK(zx::vmo::create(kSize, 0u, &buffer_vmo));
hardware_sysmem_.AddFakeVmoInfo(buffer_vmo, buffer_key);
dut_->RegisterBufferHandle(buffer_key);
fidl::Arena allocator;
fuchsia_hardware_goldfish::wire::CreateBuffer2Params create_params2(allocator);
// missing memory property
create_params2.set_size(allocator, kSize);
auto result = fidl_client_->CreateBuffer2(std::move(buffer_vmo), std::move(create_params2));
ASSERT_TRUE(result.ok());
ASSERT_TRUE(result->is_error());
ASSERT_EQ(result->error_value(), ZX_ERR_INVALID_ARGS);
dut_->FreeBufferHandle(buffer_key);
}
}
TEST_F(ControlDeviceTest, CreateBuffer2_InvalidVmo) {
constexpr size_t kSize = 65536u;
zx::vmo buffer_vmo;
ASSERT_OK(zx::vmo::create(kSize, 0u, &buffer_vmo));
// no sysmem_.AddFakeVmoInfo()
// no dut_->RegisterBufferHandle()
fidl::Arena allocator;
fuchsia_hardware_goldfish::wire::CreateBuffer2Params create_params(allocator);
create_params.set_size(allocator, kSize)
.set_memory_property(fuchsia_hardware_goldfish::wire::kMemoryPropertyDeviceLocal);
auto create_unregistered_buffer_result =
fidl_client_->CreateBuffer2(std::move(buffer_vmo), std::move(create_params));
ASSERT_TRUE(create_unregistered_buffer_result.ok());
ASSERT_TRUE(create_unregistered_buffer_result->is_error());
ASSERT_EQ(create_unregistered_buffer_result->error_value(), ZX_ERR_INVALID_ARGS);
fuchsia_hardware_goldfish::wire::CreateBuffer2Params create_params2(allocator);
create_params2.set_size(allocator, kSize)
.set_memory_property(fuchsia_hardware_goldfish::wire::kMemoryPropertyDeviceLocal);
auto create_invalid_buffer_result =
fidl_client_->CreateBuffer2(zx::vmo(), std::move(create_params2));
ASSERT_EQ(create_invalid_buffer_result.status(), ZX_ERR_INVALID_ARGS);
}
// Test |fuchsia.hardware.goldfish.Control.CreateColorBuffer2| method.
class ColorBufferTest
: public ControlDeviceTest,
public testing::WithParamInterface<
std::tuple<fuchsia_hardware_goldfish::wire::ColorBufferFormatType, uint32_t>> {};
TEST_P(ColorBufferTest, TestCreate) {
constexpr uint32_t kWidth = 1024u;
constexpr uint32_t kHeight = 768u;
constexpr uint32_t kSize = kWidth * kHeight * 4;
constexpr uint64_t kPhysicalAddress = 0x12345678abcd0000;
const auto format = std::get<0>(GetParam());
const auto memory_property = std::get<1>(GetParam());
const bool is_host_visible =
memory_property == fuchsia_hardware_goldfish::wire::kMemoryPropertyHostVisible;
const BufferKey buffer_key(14, 2);
zx::vmo buffer_vmo;
ASSERT_OK(zx::vmo::create(kSize, 0u, &buffer_vmo));
hardware_sysmem_.AddFakeVmoInfo(buffer_vmo, buffer_key);
dut_->RegisterBufferHandle(buffer_key);
fidl::Arena allocator;
fuchsia_hardware_goldfish::wire::CreateColorBuffer2Params create_params(allocator);
create_params.set_width(kWidth).set_height(kHeight).set_format(format).set_memory_property(
memory_property);
if (is_host_visible) {
create_params.set_physical_address(allocator, kPhysicalAddress);
}
auto create_color_buffer_result =
fidl_client_->CreateColorBuffer2(std::move(buffer_vmo), std::move(create_params));
ASSERT_TRUE(create_color_buffer_result.ok());
EXPECT_OK(create_color_buffer_result.value().res);
const int32_t expected_page_offset = is_host_visible ? 0 : -1;
EXPECT_EQ(create_color_buffer_result.value().hw_address_page_offset, expected_page_offset);
CreateColorBufferCmd create_color_buffer_cmd{
.op = kOP_rcCreateColorBuffer,
.size = kSize_rcCreateColorBuffer,
.width = kWidth,
.height = kHeight,
.internalformat = static_cast<uint32_t>(format),
};
SetColorBufferVulkanMode2Cmd set_vulkan_mode_cmd{
.op = kOP_rcSetColorBufferVulkanMode2,
.size = kSize_rcSetColorBufferVulkanMode2,
.id = pipe_.CurrentBufferHandle(),
.mode = 1u, // VULKAN_ONLY
.memory_property = memory_property,
};
MapGpaToBufferHandle2Cmd map_gpa_cmd{
.op = kOP_rcMapGpaToBufferHandle2,
.size = kSize_rcMapGpaToBufferHandle2,
.id = pipe_.CurrentBufferHandle(),
.gpa = kPhysicalAddress,
.map_size = kSize,
};
const auto& io_buffer_contents = pipe_.io_buffer_contents();
size_t create_color_buffer_cmd_idx = 0;
if (is_host_visible) {
ASSERT_GE(io_buffer_contents.size(), 3u);
create_color_buffer_cmd_idx = io_buffer_contents.size() - 3;
} else {
ASSERT_GE(io_buffer_contents.size(), 2u);
create_color_buffer_cmd_idx = io_buffer_contents.size() - 2;
}
EXPECT_EQ(memcmp(&create_color_buffer_cmd, io_buffer_contents[create_color_buffer_cmd_idx].data(),
sizeof(CreateColorBufferCmd)),
0);
EXPECT_EQ(memcmp(&set_vulkan_mode_cmd, io_buffer_contents[create_color_buffer_cmd_idx + 1].data(),
sizeof(set_vulkan_mode_cmd)),
0);
if (is_host_visible) {
EXPECT_EQ(memcmp(&map_gpa_cmd, io_buffer_contents[create_color_buffer_cmd_idx + 2].data(),
sizeof(MapGpaToBufferHandle2Cmd)),
0);
}
}
INSTANTIATE_TEST_SUITE_P(
ControlDeviceTest, ColorBufferTest,
testing::Combine(
testing::Values(fuchsia_hardware_goldfish::wire::ColorBufferFormatType::kRg,
fuchsia_hardware_goldfish::wire::ColorBufferFormatType::kRgba,
fuchsia_hardware_goldfish::wire::ColorBufferFormatType::kBgra,
fuchsia_hardware_goldfish::wire::ColorBufferFormatType::kLuminance),
testing::Values(fuchsia_hardware_goldfish::wire::kMemoryPropertyDeviceLocal,
fuchsia_hardware_goldfish::wire::kMemoryPropertyHostVisible)),
[](const testing::TestParamInfo<ColorBufferTest::ParamType>& info) {
std::string format;
switch (std::get<0>(info.param)) {
case fuchsia_hardware_goldfish::wire::ColorBufferFormatType::kRg:
format = "RG";
break;
case fuchsia_hardware_goldfish::wire::ColorBufferFormatType::kRgba:
format = "RGBA";
break;
case fuchsia_hardware_goldfish::wire::ColorBufferFormatType::kBgra:
format = "BGRA";
break;
case fuchsia_hardware_goldfish::wire::ColorBufferFormatType::kLuminance:
format = "LUMINANCE";
break;
default:
format = "UNSUPPORTED_FORMAT";
}
std::string memory_property;
switch (std::get<1>(info.param)) {
case fuchsia_hardware_goldfish::wire::kMemoryPropertyDeviceLocal:
memory_property = "DEVICE_LOCAL";
break;
case fuchsia_hardware_goldfish::wire::kMemoryPropertyHostVisible:
memory_property = "HOST_VISIBLE";
break;
default:
memory_property = "UNSUPPORTED_MEMORY_PROPERTY";
}
return format + "_" + memory_property;
});
TEST_F(ControlDeviceTest, CreateColorBuffer2_AlreadyExists) {
constexpr uint32_t kWidth = 1024u;
constexpr uint32_t kHeight = 768u;
constexpr uint32_t kSize = kWidth * kHeight * 4;
constexpr auto kFormat = fuchsia_hardware_goldfish::wire::ColorBufferFormatType::kRgba;
constexpr auto kMemoryProperty = fuchsia_hardware_goldfish::wire::kMemoryPropertyDeviceLocal;
const BufferKey buffer_key(15, 3);
zx::vmo buffer_vmo;
ASSERT_OK(zx::vmo::create(kSize, 0u, &buffer_vmo));
zx::vmo copy_vmo;
ASSERT_OK(buffer_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &copy_vmo));
// The object koid is the same for both VMO handles, so GetVmoInfo() will return buffer_key for
// both VMO handles.
hardware_sysmem_.AddFakeVmoInfo(buffer_vmo, buffer_key);
dut_->RegisterBufferHandle(buffer_key);
{
fidl::Arena allocator;
fuchsia_hardware_goldfish::wire::CreateColorBuffer2Params create_params(allocator);
create_params.set_width(kWidth).set_height(kHeight).set_format(kFormat).set_memory_property(
kMemoryProperty);
auto create_color_buffer_result =
fidl_client_->CreateColorBuffer2(std::move(buffer_vmo), std::move(create_params));
ASSERT_TRUE(create_color_buffer_result.ok());
EXPECT_OK(create_color_buffer_result.value().res);
}
{
fidl::Arena allocator;
fuchsia_hardware_goldfish::wire::CreateColorBuffer2Params create_params(allocator);
create_params.set_width(kWidth).set_height(kHeight).set_format(kFormat).set_memory_property(
kMemoryProperty);
auto create_copy_buffer_result =
fidl_client_->CreateColorBuffer2(std::move(copy_vmo), std::move(create_params));
ASSERT_TRUE(create_copy_buffer_result.ok());
ASSERT_EQ(create_copy_buffer_result.value().res, ZX_ERR_ALREADY_EXISTS);
}
}
TEST_F(ControlDeviceTest, CreateColorBuffer2_InvalidArgs) {
constexpr uint32_t kWidth = 1024u;
constexpr uint32_t kHeight = 768u;
constexpr uint32_t kSize = kWidth * kHeight * 4;
constexpr auto kFormat = fuchsia_hardware_goldfish::wire::ColorBufferFormatType::kRgba;
constexpr auto kMemoryProperty = fuchsia_hardware_goldfish::wire::kMemoryPropertyDeviceLocal;
{
const BufferKey buffer_key(16, 4);
zx::vmo buffer_vmo;
ASSERT_OK(zx::vmo::create(kSize, 0u, &buffer_vmo));
hardware_sysmem_.AddFakeVmoInfo(buffer_vmo, buffer_key);
dut_->RegisterBufferHandle(buffer_key);
fidl::Arena allocator;
fuchsia_hardware_goldfish::wire::CreateColorBuffer2Params create_params(allocator);
// missing width
create_params.set_height(kHeight).set_format(kFormat).set_memory_property(kMemoryProperty);
auto create_color_buffer_result =
fidl_client_->CreateColorBuffer2(std::move(buffer_vmo), std::move(create_params));
ASSERT_TRUE(create_color_buffer_result.ok());
EXPECT_EQ(create_color_buffer_result.value().res, ZX_ERR_INVALID_ARGS);
dut_->FreeBufferHandle(buffer_key);
}
{
const BufferKey buffer_key(17, 5);
zx::vmo buffer_vmo;
ASSERT_OK(zx::vmo::create(kSize, 0u, &buffer_vmo));
hardware_sysmem_.AddFakeVmoInfo(buffer_vmo, buffer_key);
dut_->RegisterBufferHandle(buffer_key);
fidl::Arena allocator;
fuchsia_hardware_goldfish::wire::CreateColorBuffer2Params create_params(allocator);
// missing height
create_params.set_width(kWidth).set_format(kFormat).set_memory_property(kMemoryProperty);
auto create_color_buffer_result =
fidl_client_->CreateColorBuffer2(std::move(buffer_vmo), std::move(create_params));
ASSERT_TRUE(create_color_buffer_result.ok());
EXPECT_EQ(create_color_buffer_result.value().res, ZX_ERR_INVALID_ARGS);
dut_->FreeBufferHandle(buffer_key);
}
{
const BufferKey buffer_key(18, 6);
zx::vmo buffer_vmo;
ASSERT_OK(zx::vmo::create(kSize, 0u, &buffer_vmo));
hardware_sysmem_.AddFakeVmoInfo(buffer_vmo, buffer_key);
dut_->RegisterBufferHandle(buffer_key);
fidl::Arena allocator;
fuchsia_hardware_goldfish::wire::CreateColorBuffer2Params create_params(allocator);
// missing format
create_params.set_width(kWidth).set_height(kHeight).set_memory_property(kMemoryProperty);
auto create_color_buffer_result =
fidl_client_->CreateColorBuffer2(std::move(buffer_vmo), std::move(create_params));
ASSERT_TRUE(create_color_buffer_result.ok());
EXPECT_EQ(create_color_buffer_result.value().res, ZX_ERR_INVALID_ARGS);
dut_->FreeBufferHandle(buffer_key);
}
{
const BufferKey buffer_key(19, 7);
zx::vmo buffer_vmo;
ASSERT_OK(zx::vmo::create(kSize, 0u, &buffer_vmo));
hardware_sysmem_.AddFakeVmoInfo(buffer_vmo, buffer_key);
dut_->RegisterBufferHandle(buffer_key);
fidl::Arena allocator;
fuchsia_hardware_goldfish::wire::CreateColorBuffer2Params create_params(allocator);
// missing memory property
create_params.set_width(kWidth).set_height(kHeight).set_format(kFormat);
auto create_color_buffer_result =
fidl_client_->CreateColorBuffer2(std::move(buffer_vmo), std::move(create_params));
ASSERT_TRUE(create_color_buffer_result.ok());
EXPECT_EQ(create_color_buffer_result.value().res, ZX_ERR_INVALID_ARGS);
dut_->FreeBufferHandle(buffer_key);
}
{
const BufferKey buffer_key(20, 8);
zx::vmo buffer_vmo;
ASSERT_OK(zx::vmo::create(kSize, 0u, &buffer_vmo));
hardware_sysmem_.AddFakeVmoInfo(buffer_vmo, buffer_key);
dut_->RegisterBufferHandle(buffer_key);
fidl::Arena allocator;
fuchsia_hardware_goldfish::wire::CreateColorBuffer2Params create_params(allocator);
// missing physical address
create_params.set_width(kWidth).set_height(kHeight).set_format(kFormat).set_memory_property(
fuchsia_hardware_goldfish::wire::kMemoryPropertyHostVisible);
auto create_color_buffer_result =
fidl_client_->CreateColorBuffer2(std::move(buffer_vmo), std::move(create_params));
ASSERT_TRUE(create_color_buffer_result.ok());
EXPECT_EQ(create_color_buffer_result.value().res, ZX_ERR_INVALID_ARGS);
dut_->FreeBufferHandle(buffer_key);
}
}
TEST_F(ControlDeviceTest, CreateColorBuffer2_InvalidVmo) {
constexpr uint32_t kWidth = 1024u;
constexpr uint32_t kHeight = 768u;
constexpr uint32_t kSize = kWidth * kHeight * 4;
constexpr auto kFormat = fuchsia_hardware_goldfish::wire::ColorBufferFormatType::kRgba;
constexpr auto kMemoryProperty = fuchsia_hardware_goldfish::wire::kMemoryPropertyDeviceLocal;
zx::vmo buffer_vmo;
ASSERT_OK(zx::vmo::create(kSize, 0u, &buffer_vmo));
// no sysmem_.AddVakeVmoInfo()
// no dut_->RegisterBufferHandle()
{
fidl::Arena allocator;
fuchsia_hardware_goldfish::wire::CreateColorBuffer2Params create_params(allocator);
create_params.set_width(kWidth).set_height(kHeight).set_format(kFormat).set_memory_property(
kMemoryProperty);
auto create_unregistered_buffer_result =
fidl_client_->CreateColorBuffer2(std::move(buffer_vmo), std::move(create_params));
ASSERT_TRUE(create_unregistered_buffer_result.ok());
EXPECT_EQ(create_unregistered_buffer_result.value().res, ZX_ERR_INVALID_ARGS);
}
{
fidl::Arena allocator;
fuchsia_hardware_goldfish::wire::CreateColorBuffer2Params create_params(allocator);
create_params.set_width(kWidth).set_height(kHeight).set_format(kFormat).set_memory_property(
kMemoryProperty);
auto create_invalid_buffer_result =
fidl_client_->CreateColorBuffer2(zx::vmo(), std::move(create_params));
ASSERT_EQ(create_invalid_buffer_result.status(), ZX_ERR_INVALID_ARGS);
}
}
// Test |fuchsia.hardware.goldfish.Control.GetBufferHandle| method.
TEST_F(ControlDeviceTest, GetBufferHandle_Success) {
zx::vmo buffer_vmo, buffer_vmo_dup;
zx::vmo color_buffer_vmo, color_buffer_vmo_dup;
// Create data buffer.
{
const BufferKey buffer_key(21, 20);
constexpr size_t kSize = 65536u;
ASSERT_OK(zx::vmo::create(kSize, 0u, &buffer_vmo));
ASSERT_OK(buffer_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &buffer_vmo_dup));
zx::vmo copy_vmo;
ASSERT_OK(buffer_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &copy_vmo));
hardware_sysmem_.AddFakeVmoInfo(buffer_vmo, buffer_key);
dut_->RegisterBufferHandle(buffer_key);
fidl::Arena allocator;
fuchsia_hardware_goldfish::wire::CreateBuffer2Params create_params(allocator);
create_params.set_size(allocator, kSize)
.set_memory_property(fuchsia_hardware_goldfish::wire::kMemoryPropertyDeviceLocal);
auto create_buffer_result =
fidl_client_->CreateBuffer2(std::move(copy_vmo), std::move(create_params));
ASSERT_TRUE(create_buffer_result.ok());
EXPECT_TRUE(create_buffer_result->is_ok());
}
// Create color buffer.
{
const BufferKey buffer_key(22, 21);
constexpr uint32_t kWidth = 1024u;
constexpr uint32_t kHeight = 768u;
constexpr uint32_t kSize = kWidth * kHeight * 4;
constexpr auto kFormat = fuchsia_hardware_goldfish::wire::ColorBufferFormatType::kRgba;
constexpr auto kMemoryProperty = fuchsia_hardware_goldfish::wire::kMemoryPropertyDeviceLocal;
ASSERT_OK(zx::vmo::create(kSize, 0u, &color_buffer_vmo));
ASSERT_OK(color_buffer_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &color_buffer_vmo_dup));
zx::vmo copy_vmo;
ASSERT_OK(color_buffer_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &copy_vmo));
hardware_sysmem_.AddFakeVmoInfo(color_buffer_vmo, buffer_key);
dut_->RegisterBufferHandle(buffer_key);
fidl::Arena allocator;
fuchsia_hardware_goldfish::wire::CreateColorBuffer2Params create_params(allocator);
create_params.set_width(kWidth).set_height(kHeight).set_format(kFormat).set_memory_property(
kMemoryProperty);
auto create_color_buffer_result =
fidl_client_->CreateColorBuffer2(std::move(copy_vmo), std::move(create_params));
ASSERT_TRUE(create_color_buffer_result.ok());
EXPECT_OK(create_color_buffer_result.value().res);
}
// Test GetBufferHandle() method.
auto get_buffer_handle_result = fidl_client_->GetBufferHandle(std::move(buffer_vmo));
ASSERT_TRUE(get_buffer_handle_result.ok());
EXPECT_OK(get_buffer_handle_result.value().res);
EXPECT_NE(get_buffer_handle_result.value().id, 0u);
EXPECT_EQ(get_buffer_handle_result.value().type,
fuchsia_hardware_goldfish::wire::BufferHandleType::kBuffer);
auto get_color_buffer_handle_result = fidl_client_->GetBufferHandle(std::move(color_buffer_vmo));
ASSERT_TRUE(get_color_buffer_handle_result.ok());
EXPECT_OK(get_color_buffer_handle_result.value().res);
EXPECT_NE(get_color_buffer_handle_result.value().id, 0u);
EXPECT_NE(get_color_buffer_handle_result.value().id, get_buffer_handle_result.value().id);
EXPECT_EQ(get_color_buffer_handle_result.value().type,
fuchsia_hardware_goldfish::wire::BufferHandleType::kColorBuffer);
// Test GetBufferHandleInfo() method.
auto get_buffer_handle_info_result = fidl_client_->GetBufferHandleInfo(std::move(buffer_vmo_dup));
ASSERT_TRUE(get_buffer_handle_info_result.ok());
ASSERT_TRUE(get_buffer_handle_info_result->is_ok());
const auto& buffer_handle_info = get_buffer_handle_info_result->value()->info;
EXPECT_NE(buffer_handle_info.id(), 0u);
EXPECT_EQ(buffer_handle_info.type(), fuchsia_hardware_goldfish::wire::BufferHandleType::kBuffer);
EXPECT_EQ(buffer_handle_info.memory_property(),
fuchsia_hardware_goldfish::wire::kMemoryPropertyDeviceLocal);
auto get_color_buffer_handle_info_result =
fidl_client_->GetBufferHandleInfo(std::move(color_buffer_vmo_dup));
ASSERT_TRUE(get_color_buffer_handle_info_result.ok());
ASSERT_TRUE(get_color_buffer_handle_info_result->is_ok());
const auto& color_buffer_handle_info = get_color_buffer_handle_info_result->value()->info;
EXPECT_NE(color_buffer_handle_info.id(), 0u);
EXPECT_EQ(color_buffer_handle_info.type(),
fuchsia_hardware_goldfish::wire::BufferHandleType::kColorBuffer);
EXPECT_EQ(color_buffer_handle_info.memory_property(),
fuchsia_hardware_goldfish::wire::kMemoryPropertyDeviceLocal);
}
TEST_F(ControlDeviceTest, GetBufferHandle_Invalid) {
// Register data buffer, but don't create it.
{
const BufferKey buffer_key(23, 22);
constexpr size_t kSize = 65536u;
zx::vmo buffer_vmo;
ASSERT_OK(zx::vmo::create(kSize, 0u, &buffer_vmo));
hardware_sysmem_.AddFakeVmoInfo(buffer_vmo, buffer_key);
dut_->RegisterBufferHandle(buffer_key);
auto get_buffer_handle_result = fidl_client_->GetBufferHandle(std::move(buffer_vmo));
ASSERT_TRUE(get_buffer_handle_result.ok());
EXPECT_EQ(get_buffer_handle_result.value().res, ZX_ERR_NOT_FOUND);
dut_->FreeBufferHandle(buffer_key);
}
// Check non-registered buffer VMO.
{
constexpr size_t kSize = 65536u;
zx::vmo buffer_vmo;
ASSERT_OK(zx::vmo::create(kSize, 0u, &buffer_vmo));
auto get_buffer_handle_result = fidl_client_->GetBufferHandle(std::move(buffer_vmo));
ASSERT_TRUE(get_buffer_handle_result.ok());
EXPECT_EQ(get_buffer_handle_result.value().res, ZX_ERR_INVALID_ARGS);
}
// Check invalid buffer VMO.
{
auto get_buffer_handle_result = fidl_client_->GetBufferHandle(zx::vmo());
ASSERT_EQ(get_buffer_handle_result.status(), ZX_ERR_INVALID_ARGS);
}
}
TEST_F(ControlDeviceTest, GetBufferHandleInfo_Invalid) {
// Register data buffer, but don't create it.
{
const BufferKey buffer_key(24, 23);
constexpr size_t kSize = 65536u;
zx::vmo buffer_vmo;
ASSERT_OK(zx::vmo::create(kSize, 0u, &buffer_vmo));
hardware_sysmem_.AddFakeVmoInfo(buffer_vmo, buffer_key);
dut_->RegisterBufferHandle(buffer_key);
auto get_buffer_handle_info_result = fidl_client_->GetBufferHandleInfo(std::move(buffer_vmo));
ASSERT_TRUE(get_buffer_handle_info_result.ok());
EXPECT_TRUE(get_buffer_handle_info_result->is_error());
EXPECT_EQ(get_buffer_handle_info_result->error_value(), ZX_ERR_NOT_FOUND);
dut_->FreeBufferHandle(buffer_key);
}
// Check non-registered buffer VMO.
{
constexpr size_t kSize = 65536u;
zx::vmo buffer_vmo;
ASSERT_OK(zx::vmo::create(kSize, 0u, &buffer_vmo));
auto get_buffer_handle_info_result = fidl_client_->GetBufferHandleInfo(std::move(buffer_vmo));
ASSERT_TRUE(get_buffer_handle_info_result.ok());
EXPECT_TRUE(get_buffer_handle_info_result->is_error());
EXPECT_EQ(get_buffer_handle_info_result->error_value(), ZX_ERR_INVALID_ARGS);
}
// Check invalid buffer VMO.
{
auto get_buffer_handle_info_result = fidl_client_->GetBufferHandleInfo(zx::vmo());
ASSERT_EQ(get_buffer_handle_info_result.status(), ZX_ERR_INVALID_ARGS);
}
}
} // namespace
} // namespace goldfish