blob: 09e209dd70ad82e52fe4b7e4e080e8b7b64285da [file] [log] [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "mojo/public/cpp/system/platform_handle.h"
#include "base/check_op.h"
#include "base/memory/platform_shared_memory_region.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "build/build_config.h"
#include "mojo/public/cpp/platform/platform_handle_internal.h"
namespace mojo {
namespace {
uint64_t ReleasePlatformHandleValueFromPlatformFile(
base::ScopedPlatformFile file) {
#if BUILDFLAG(IS_WIN)
return reinterpret_cast<uint64_t>(file.Take());
#else
return static_cast<uint64_t>(file.release());
#endif
}
base::ScopedPlatformFile PlatformFileFromPlatformHandleValue(uint64_t value) {
#if BUILDFLAG(IS_WIN)
return base::ScopedPlatformFile(reinterpret_cast<base::PlatformFile>(value));
#else
return base::ScopedPlatformFile(static_cast<base::PlatformFile>(value));
#endif
}
} // namespace
ScopedSharedBufferHandle WrapPlatformSharedMemoryRegion(
base::subtle::PlatformSharedMemoryRegion region) {
if (!region.IsValid())
return ScopedSharedBufferHandle();
MojoPlatformSharedMemoryRegionAccessMode access_mode;
switch (region.GetMode()) {
case base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly:
access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY;
break;
case base::subtle::PlatformSharedMemoryRegion::Mode::kWritable:
access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE;
break;
case base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe:
access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE;
break;
default:
NOTREACHED();
return ScopedSharedBufferHandle();
}
base::subtle::ScopedPlatformSharedMemoryHandle handle =
region.PassPlatformHandle();
MojoPlatformHandle platform_handles[2];
uint32_t num_platform_handles = 1;
platform_handles[0].struct_size = sizeof(platform_handles[0]);
#if BUILDFLAG(IS_WIN)
platform_handles[0].type = MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE;
platform_handles[0].value = reinterpret_cast<uint64_t>(handle.Take());
#elif BUILDFLAG(IS_FUCHSIA)
platform_handles[0].type = MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE;
platform_handles[0].value = static_cast<uint64_t>(handle.release());
#elif BUILDFLAG(IS_APPLE)
platform_handles[0].type = MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT;
platform_handles[0].value = static_cast<uint64_t>(handle.release());
#elif BUILDFLAG(IS_ANDROID)
platform_handles[0].type = MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR;
platform_handles[0].value = static_cast<uint64_t>(handle.release());
#else
platform_handles[0].type = MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR;
platform_handles[0].value = static_cast<uint64_t>(handle.fd.release());
if (region.GetMode() ==
base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) {
num_platform_handles = 2;
platform_handles[1].struct_size = sizeof(platform_handles[1]);
platform_handles[1].type = MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR;
platform_handles[1].value =
static_cast<uint64_t>(handle.readonly_fd.release());
}
#endif
MojoSharedBufferGuid mojo_guid =
mojo::internal::PlatformHandleInternal::MarshalUnguessableToken(
region.GetGUID());
MojoHandle mojo_handle;
MojoResult result = MojoWrapPlatformSharedMemoryRegion(
platform_handles, num_platform_handles, region.GetSize(), &mojo_guid,
access_mode, nullptr, &mojo_handle);
if (result != MOJO_RESULT_OK)
return ScopedSharedBufferHandle();
return ScopedSharedBufferHandle(SharedBufferHandle(mojo_handle));
}
base::subtle::PlatformSharedMemoryRegion UnwrapPlatformSharedMemoryRegion(
ScopedSharedBufferHandle mojo_handle) {
if (!mojo_handle.is_valid())
return base::subtle::PlatformSharedMemoryRegion();
MojoPlatformHandle platform_handles[2];
platform_handles[0].struct_size = sizeof(platform_handles[0]);
platform_handles[1].struct_size = sizeof(platform_handles[1]);
uint32_t num_platform_handles = 2;
uint64_t size;
MojoSharedBufferGuid mojo_guid;
MojoPlatformSharedMemoryRegionAccessMode access_mode;
MojoResult result = MojoUnwrapPlatformSharedMemoryRegion(
mojo_handle.release().value(), nullptr, platform_handles,
&num_platform_handles, &size, &mojo_guid, &access_mode);
if (result != MOJO_RESULT_OK)
return base::subtle::PlatformSharedMemoryRegion();
base::subtle::ScopedPlatformSharedMemoryHandle region_handle;
#if BUILDFLAG(IS_WIN)
if (num_platform_handles != 1)
return base::subtle::PlatformSharedMemoryRegion();
if (platform_handles[0].type != MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE)
return base::subtle::PlatformSharedMemoryRegion();
region_handle.Set(reinterpret_cast<HANDLE>(platform_handles[0].value));
#elif BUILDFLAG(IS_FUCHSIA)
if (num_platform_handles != 1)
return base::subtle::PlatformSharedMemoryRegion();
if (platform_handles[0].type != MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE)
return base::subtle::PlatformSharedMemoryRegion();
region_handle.reset(static_cast<zx_handle_t>(platform_handles[0].value));
#elif BUILDFLAG(IS_APPLE)
if (num_platform_handles != 1)
return base::subtle::PlatformSharedMemoryRegion();
if (platform_handles[0].type != MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT)
return base::subtle::PlatformSharedMemoryRegion();
region_handle.reset(static_cast<mach_port_t>(platform_handles[0].value));
#elif BUILDFLAG(IS_ANDROID)
if (num_platform_handles != 1)
return base::subtle::PlatformSharedMemoryRegion();
if (platform_handles[0].type != MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR)
return base::subtle::PlatformSharedMemoryRegion();
region_handle.reset(static_cast<int>(platform_handles[0].value));
#else
if (access_mode == MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE) {
if (num_platform_handles != 2)
return base::subtle::PlatformSharedMemoryRegion();
} else if (num_platform_handles != 1) {
return base::subtle::PlatformSharedMemoryRegion();
}
if (platform_handles[0].type != MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR)
return base::subtle::PlatformSharedMemoryRegion();
region_handle.fd.reset(static_cast<int>(platform_handles[0].value));
if (num_platform_handles == 2) {
if (platform_handles[1].type != MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR)
return base::subtle::PlatformSharedMemoryRegion();
region_handle.readonly_fd.reset(
static_cast<int>(platform_handles[1].value));
}
#endif
base::subtle::PlatformSharedMemoryRegion::Mode mode;
switch (access_mode) {
case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY:
mode = base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly;
break;
case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE:
mode = base::subtle::PlatformSharedMemoryRegion::Mode::kWritable;
break;
case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE:
mode = base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe;
break;
default:
return base::subtle::PlatformSharedMemoryRegion();
}
std::optional<base::UnguessableToken> guid =
internal::PlatformHandleInternal::UnmarshalUnguessableToken(&mojo_guid);
if (!guid.has_value()) {
return base::subtle::PlatformSharedMemoryRegion();
}
return base::subtle::PlatformSharedMemoryRegion::Take(
std::move(region_handle), mode, size, guid.value());
}
ScopedHandle WrapPlatformHandle(PlatformHandle handle) {
if (!handle.is_valid()) {
return ScopedHandle();
}
MojoPlatformHandle platform_handle;
PlatformHandle::ToMojoPlatformHandle(std::move(handle), &platform_handle);
MojoHandle wrapped_handle;
MojoResult result =
MojoWrapPlatformHandle(&platform_handle, nullptr, &wrapped_handle);
if (result != MOJO_RESULT_OK)
return ScopedHandle();
return ScopedHandle(Handle(wrapped_handle));
}
PlatformHandle UnwrapPlatformHandle(ScopedHandle handle) {
if (!handle.is_valid()) {
return PlatformHandle();
}
MojoPlatformHandle platform_handle;
platform_handle.struct_size = sizeof(platform_handle);
MojoResult result = MojoUnwrapPlatformHandle(handle.release().value(),
nullptr, &platform_handle);
if (result != MOJO_RESULT_OK)
return PlatformHandle();
return PlatformHandle::FromMojoPlatformHandle(&platform_handle);
}
ScopedHandle WrapPlatformFile(base::ScopedPlatformFile platform_file) {
MojoPlatformHandle platform_handle;
platform_handle.struct_size = sizeof(MojoPlatformHandle);
platform_handle.type = kPlatformFileHandleType;
platform_handle.value =
ReleasePlatformHandleValueFromPlatformFile(std::move(platform_file));
MojoHandle mojo_handle;
MojoResult result =
MojoWrapPlatformHandle(&platform_handle, nullptr, &mojo_handle);
CHECK_EQ(result, MOJO_RESULT_OK);
return ScopedHandle(Handle(mojo_handle));
}
MojoResult UnwrapPlatformFile(ScopedHandle handle,
base::ScopedPlatformFile* file) {
MojoPlatformHandle platform_handle;
platform_handle.struct_size = sizeof(MojoPlatformHandle);
MojoResult result = MojoUnwrapPlatformHandle(handle.release().value(),
nullptr, &platform_handle);
if (result != MOJO_RESULT_OK)
return result;
if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_INVALID) {
*file = base::ScopedPlatformFile();
} else {
CHECK_EQ(platform_handle.type, kPlatformFileHandleType);
*file = PlatformFileFromPlatformHandleValue(platform_handle.value);
}
return MOJO_RESULT_OK;
}
ScopedSharedBufferHandle WrapReadOnlySharedMemoryRegion(
base::ReadOnlySharedMemoryRegion region) {
return WrapPlatformSharedMemoryRegion(
base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization(
std::move(region)));
}
ScopedSharedBufferHandle WrapUnsafeSharedMemoryRegion(
base::UnsafeSharedMemoryRegion region) {
return WrapPlatformSharedMemoryRegion(
base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
std::move(region)));
}
ScopedSharedBufferHandle WrapWritableSharedMemoryRegion(
base::WritableSharedMemoryRegion region) {
return WrapPlatformSharedMemoryRegion(
base::WritableSharedMemoryRegion::TakeHandleForSerialization(
std::move(region)));
}
base::ReadOnlySharedMemoryRegion UnwrapReadOnlySharedMemoryRegion(
ScopedSharedBufferHandle handle) {
return base::ReadOnlySharedMemoryRegion::Deserialize(
UnwrapPlatformSharedMemoryRegion(std::move(handle)));
}
base::UnsafeSharedMemoryRegion UnwrapUnsafeSharedMemoryRegion(
ScopedSharedBufferHandle handle) {
return base::UnsafeSharedMemoryRegion::Deserialize(
UnwrapPlatformSharedMemoryRegion(std::move(handle)));
}
base::WritableSharedMemoryRegion UnwrapWritableSharedMemoryRegion(
ScopedSharedBufferHandle handle) {
return base::WritableSharedMemoryRegion::Deserialize(
UnwrapPlatformSharedMemoryRegion(std::move(handle)));
}
} // namespace mojo