You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
487 lines
19 KiB
487 lines
19 KiB
// Copyright 2013 The Chromium 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 "mojo/public/c/system/thunks.h"
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
|
|
#include "base/logging.h"
|
|
#include "base/macros.h"
|
|
#include "base/memory/protected_memory.h"
|
|
#include "base/memory/protected_memory_cfi.h"
|
|
#include "base/no_destructor.h"
|
|
#include "build/build_config.h"
|
|
#include "mojo/public/c/system/core.h"
|
|
|
|
#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN)
|
|
#include "base/environment.h"
|
|
#include "base/files/file_path.h"
|
|
#include "base/optional.h"
|
|
#include "base/scoped_native_library.h"
|
|
#include "base/threading/thread_restrictions.h"
|
|
#endif
|
|
|
|
namespace {
|
|
|
|
typedef void (*MojoGetSystemThunksFunction)(MojoSystemThunks* thunks);
|
|
|
|
#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN)
|
|
PROTECTED_MEMORY_SECTION
|
|
base::ProtectedMemory<MojoGetSystemThunksFunction> g_get_thunks;
|
|
#endif
|
|
|
|
PROTECTED_MEMORY_SECTION base::ProtectedMemory<MojoSystemThunks> g_thunks;
|
|
|
|
MojoResult NotImplemented(const char* name) {
|
|
DLOG(ERROR) << "Function 'Mojo" << name
|
|
<< "()' not supported in this version of Mojo Core.";
|
|
return MOJO_RESULT_UNIMPLEMENTED;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
// Macro to verify that the thunk symbol |name| is actually present in the
|
|
// runtime version of Mojo Core that is currently in use.
|
|
#define FUNCTION_IS_IMPLEMENTED(name) \
|
|
(reinterpret_cast<uintptr_t>(static_cast<const void*>(&g_thunks->name)) - \
|
|
reinterpret_cast<uintptr_t>(static_cast<const void*>(&g_thunks)) < \
|
|
g_thunks->size)
|
|
|
|
#define INVOKE_THUNK(name, ...) \
|
|
FUNCTION_IS_IMPLEMENTED(name) \
|
|
? base::UnsanitizedCfiCall(g_thunks, &MojoSystemThunks::name)(__VA_ARGS__) \
|
|
: NotImplemented(#name)
|
|
|
|
namespace mojo {
|
|
|
|
// NOTE: This is defined within the global mojo namespace so that it can be
|
|
// referenced as a friend to base::ScopedAllowBlocking when library support is
|
|
// enabled.
|
|
class CoreLibraryInitializer {
|
|
public:
|
|
CoreLibraryInitializer(const MojoInitializeOptions* options) {
|
|
#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN)
|
|
bool application_provided_path = false;
|
|
base::Optional<base::FilePath> library_path;
|
|
if (options && options->struct_size >= sizeof(*options) &&
|
|
options->mojo_core_path) {
|
|
base::StringPiece utf8_path(options->mojo_core_path,
|
|
options->mojo_core_path_length);
|
|
library_path.emplace(base::FilePath::FromUTF8Unsafe(utf8_path));
|
|
application_provided_path = true;
|
|
} else {
|
|
auto environment = base::Environment::Create();
|
|
std::string library_path_value;
|
|
const char kLibraryPathEnvironmentVar[] = "MOJO_CORE_LIBRARY_PATH";
|
|
if (environment->GetVar(kLibraryPathEnvironmentVar, &library_path_value))
|
|
library_path = base::FilePath::FromUTF8Unsafe(library_path_value);
|
|
}
|
|
|
|
if (!library_path) {
|
|
// Default to looking for the library in the current working directory.
|
|
#if defined(OS_CHROMEOS) || defined(OS_LINUX)
|
|
const base::FilePath::CharType kDefaultLibraryPathValue[] =
|
|
FILE_PATH_LITERAL("./libmojo_core.so");
|
|
#elif defined(OS_WIN)
|
|
const base::FilePath::CharType kDefaultLibraryPathValue[] =
|
|
FILE_PATH_LITERAL("mojo_core.dll");
|
|
#endif
|
|
library_path.emplace(kDefaultLibraryPathValue);
|
|
}
|
|
|
|
base::ScopedAllowBlocking allow_blocking;
|
|
library_.emplace(*library_path);
|
|
if (!application_provided_path) {
|
|
CHECK(library_->is_valid())
|
|
<< "Unable to load the mojo_core library. Make sure the library is "
|
|
<< "in the working directory or is correctly pointed to by the "
|
|
<< "MOJO_CORE_LIBRARY_PATH environment variable.";
|
|
} else {
|
|
CHECK(library_->is_valid())
|
|
<< "Unable to locate mojo_core library. This application expects to "
|
|
<< "find it at " << library_path->value();
|
|
}
|
|
|
|
const char kGetThunksFunctionName[] = "MojoGetSystemThunks";
|
|
{
|
|
auto writer = base::AutoWritableMemory::Create(g_get_thunks);
|
|
*g_get_thunks = reinterpret_cast<MojoGetSystemThunksFunction>(
|
|
library_->GetFunctionPointer(kGetThunksFunctionName));
|
|
}
|
|
CHECK(*g_get_thunks) << "Invalid mojo_core library: "
|
|
<< library_path->value();
|
|
|
|
DCHECK_EQ(g_thunks->size, 0u);
|
|
{
|
|
auto writer = base::AutoWritableMemory::Create(g_thunks);
|
|
g_thunks->size = sizeof(*g_thunks);
|
|
base::UnsanitizedCfiCall(g_get_thunks)(&*g_thunks);
|
|
}
|
|
|
|
CHECK_GT(g_thunks->size, 0u)
|
|
<< "Invalid mojo_core library: " << library_path->value();
|
|
#else // defined(OS_CHROMEOS) || defined(OS_LINUX)
|
|
NOTREACHED()
|
|
<< "Dynamic mojo_core loading is not supported on this platform.";
|
|
#endif // defined(OS_CHROMEOS) || defined(OS_LINUX)
|
|
}
|
|
|
|
~CoreLibraryInitializer() = default;
|
|
|
|
private:
|
|
#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN)
|
|
base::Optional<base::ScopedNativeLibrary> library_;
|
|
#endif
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(CoreLibraryInitializer);
|
|
};
|
|
|
|
} // namespace mojo
|
|
|
|
extern "C" {
|
|
|
|
MojoResult MojoInitialize(const struct MojoInitializeOptions* options) {
|
|
static base::NoDestructor<mojo::CoreLibraryInitializer> initializer(options);
|
|
ALLOW_UNUSED_LOCAL(initializer);
|
|
DCHECK(g_thunks->Initialize);
|
|
|
|
return INVOKE_THUNK(Initialize, options);
|
|
}
|
|
|
|
MojoTimeTicks MojoGetTimeTicksNow() {
|
|
return INVOKE_THUNK(GetTimeTicksNow);
|
|
}
|
|
|
|
MojoResult MojoClose(MojoHandle handle) {
|
|
return INVOKE_THUNK(Close, handle);
|
|
}
|
|
|
|
MojoResult MojoQueryHandleSignalsState(
|
|
MojoHandle handle,
|
|
struct MojoHandleSignalsState* signals_state) {
|
|
return INVOKE_THUNK(QueryHandleSignalsState, handle, signals_state);
|
|
}
|
|
|
|
MojoResult MojoCreateMessagePipe(const MojoCreateMessagePipeOptions* options,
|
|
MojoHandle* message_pipe_handle0,
|
|
MojoHandle* message_pipe_handle1) {
|
|
return INVOKE_THUNK(CreateMessagePipe, options, message_pipe_handle0,
|
|
message_pipe_handle1);
|
|
}
|
|
|
|
MojoResult MojoWriteMessage(MojoHandle message_pipe_handle,
|
|
MojoMessageHandle message_handle,
|
|
const MojoWriteMessageOptions* options) {
|
|
return INVOKE_THUNK(WriteMessage, message_pipe_handle, message_handle,
|
|
options);
|
|
}
|
|
|
|
MojoResult MojoReadMessage(MojoHandle message_pipe_handle,
|
|
const MojoReadMessageOptions* options,
|
|
MojoMessageHandle* message_handle) {
|
|
return INVOKE_THUNK(ReadMessage, message_pipe_handle, options,
|
|
message_handle);
|
|
}
|
|
|
|
MojoResult MojoFuseMessagePipes(MojoHandle handle0,
|
|
MojoHandle handle1,
|
|
const MojoFuseMessagePipesOptions* options) {
|
|
return INVOKE_THUNK(FuseMessagePipes, handle0, handle1, options);
|
|
}
|
|
|
|
MojoResult MojoCreateDataPipe(const MojoCreateDataPipeOptions* options,
|
|
MojoHandle* data_pipe_producer_handle,
|
|
MojoHandle* data_pipe_consumer_handle) {
|
|
return INVOKE_THUNK(CreateDataPipe, options, data_pipe_producer_handle,
|
|
data_pipe_consumer_handle);
|
|
}
|
|
|
|
MojoResult MojoWriteData(MojoHandle data_pipe_producer_handle,
|
|
const void* elements,
|
|
uint32_t* num_elements,
|
|
const MojoWriteDataOptions* options) {
|
|
return INVOKE_THUNK(WriteData, data_pipe_producer_handle, elements,
|
|
num_elements, options);
|
|
}
|
|
|
|
MojoResult MojoBeginWriteData(MojoHandle data_pipe_producer_handle,
|
|
const MojoBeginWriteDataOptions* options,
|
|
void** buffer,
|
|
uint32_t* buffer_num_elements) {
|
|
return INVOKE_THUNK(BeginWriteData, data_pipe_producer_handle, options,
|
|
buffer, buffer_num_elements);
|
|
}
|
|
|
|
MojoResult MojoEndWriteData(MojoHandle data_pipe_producer_handle,
|
|
uint32_t num_elements_written,
|
|
const MojoEndWriteDataOptions* options) {
|
|
return INVOKE_THUNK(EndWriteData, data_pipe_producer_handle,
|
|
num_elements_written, options);
|
|
}
|
|
|
|
MojoResult MojoReadData(MojoHandle data_pipe_consumer_handle,
|
|
const MojoReadDataOptions* options,
|
|
void* elements,
|
|
uint32_t* num_elements) {
|
|
return INVOKE_THUNK(ReadData, data_pipe_consumer_handle, options, elements,
|
|
num_elements);
|
|
}
|
|
|
|
MojoResult MojoBeginReadData(MojoHandle data_pipe_consumer_handle,
|
|
const MojoBeginReadDataOptions* options,
|
|
const void** buffer,
|
|
uint32_t* buffer_num_elements) {
|
|
return INVOKE_THUNK(BeginReadData, data_pipe_consumer_handle, options, buffer,
|
|
buffer_num_elements);
|
|
}
|
|
|
|
MojoResult MojoEndReadData(MojoHandle data_pipe_consumer_handle,
|
|
uint32_t num_elements_read,
|
|
const MojoEndReadDataOptions* options) {
|
|
return INVOKE_THUNK(EndReadData, data_pipe_consumer_handle, num_elements_read,
|
|
options);
|
|
}
|
|
|
|
MojoResult MojoCreateSharedBuffer(uint64_t num_bytes,
|
|
const MojoCreateSharedBufferOptions* options,
|
|
MojoHandle* shared_buffer_handle) {
|
|
return INVOKE_THUNK(CreateSharedBuffer, num_bytes, options,
|
|
shared_buffer_handle);
|
|
}
|
|
|
|
MojoResult MojoDuplicateBufferHandle(
|
|
MojoHandle buffer_handle,
|
|
const MojoDuplicateBufferHandleOptions* options,
|
|
MojoHandle* new_buffer_handle) {
|
|
return INVOKE_THUNK(DuplicateBufferHandle, buffer_handle, options,
|
|
new_buffer_handle);
|
|
}
|
|
|
|
MojoResult MojoMapBuffer(MojoHandle buffer_handle,
|
|
uint64_t offset,
|
|
uint64_t num_bytes,
|
|
const MojoMapBufferOptions* options,
|
|
void** buffer) {
|
|
return INVOKE_THUNK(MapBuffer, buffer_handle, offset, num_bytes, options,
|
|
buffer);
|
|
}
|
|
|
|
MojoResult MojoUnmapBuffer(void* buffer) {
|
|
return INVOKE_THUNK(UnmapBuffer, buffer);
|
|
}
|
|
|
|
MojoResult MojoGetBufferInfo(MojoHandle buffer_handle,
|
|
const MojoGetBufferInfoOptions* options,
|
|
MojoSharedBufferInfo* info) {
|
|
return INVOKE_THUNK(GetBufferInfo, buffer_handle, options, info);
|
|
}
|
|
|
|
MojoResult MojoCreateTrap(MojoTrapEventHandler handler,
|
|
const MojoCreateTrapOptions* options,
|
|
MojoHandle* trap_handle) {
|
|
return INVOKE_THUNK(CreateTrap, handler, options, trap_handle);
|
|
}
|
|
|
|
MojoResult MojoAddTrigger(MojoHandle trap_handle,
|
|
MojoHandle handle,
|
|
MojoHandleSignals signals,
|
|
MojoTriggerCondition condition,
|
|
uintptr_t context,
|
|
const MojoAddTriggerOptions* options) {
|
|
return INVOKE_THUNK(AddTrigger, trap_handle, handle, signals, condition,
|
|
context, options);
|
|
}
|
|
|
|
MojoResult MojoRemoveTrigger(MojoHandle trap_handle,
|
|
uintptr_t context,
|
|
const MojoRemoveTriggerOptions* options) {
|
|
return INVOKE_THUNK(RemoveTrigger, trap_handle, context, options);
|
|
}
|
|
|
|
MojoResult MojoArmTrap(MojoHandle trap_handle,
|
|
const MojoArmTrapOptions* options,
|
|
uint32_t* num_blocking_events,
|
|
MojoTrapEvent* blocking_events) {
|
|
return INVOKE_THUNK(ArmTrap, trap_handle, options, num_blocking_events,
|
|
blocking_events);
|
|
}
|
|
|
|
MojoResult MojoCreateMessage(const MojoCreateMessageOptions* options,
|
|
MojoMessageHandle* message) {
|
|
return INVOKE_THUNK(CreateMessage, options, message);
|
|
}
|
|
|
|
MojoResult MojoDestroyMessage(MojoMessageHandle message) {
|
|
return INVOKE_THUNK(DestroyMessage, message);
|
|
}
|
|
|
|
MojoResult MojoSerializeMessage(MojoMessageHandle message,
|
|
const MojoSerializeMessageOptions* options) {
|
|
return INVOKE_THUNK(SerializeMessage, message, options);
|
|
}
|
|
|
|
MojoResult MojoAppendMessageData(MojoMessageHandle message,
|
|
uint32_t payload_size,
|
|
const MojoHandle* handles,
|
|
uint32_t num_handles,
|
|
const MojoAppendMessageDataOptions* options,
|
|
void** buffer,
|
|
uint32_t* buffer_size) {
|
|
return INVOKE_THUNK(AppendMessageData, message, payload_size, handles,
|
|
num_handles, options, buffer, buffer_size);
|
|
}
|
|
|
|
MojoResult MojoGetMessageData(MojoMessageHandle message,
|
|
const MojoGetMessageDataOptions* options,
|
|
void** buffer,
|
|
uint32_t* num_bytes,
|
|
MojoHandle* handles,
|
|
uint32_t* num_handles) {
|
|
return INVOKE_THUNK(GetMessageData, message, options, buffer, num_bytes,
|
|
handles, num_handles);
|
|
}
|
|
|
|
MojoResult MojoSetMessageContext(MojoMessageHandle message,
|
|
uintptr_t context,
|
|
MojoMessageContextSerializer serializer,
|
|
MojoMessageContextDestructor destructor,
|
|
const MojoSetMessageContextOptions* options) {
|
|
return INVOKE_THUNK(SetMessageContext, message, context, serializer,
|
|
destructor, options);
|
|
}
|
|
|
|
MojoResult MojoGetMessageContext(MojoMessageHandle message,
|
|
const MojoGetMessageContextOptions* options,
|
|
uintptr_t* context) {
|
|
return INVOKE_THUNK(GetMessageContext, message, options, context);
|
|
}
|
|
|
|
MojoResult MojoNotifyBadMessage(MojoMessageHandle message,
|
|
const char* error,
|
|
uint32_t error_num_bytes,
|
|
const MojoNotifyBadMessageOptions* options) {
|
|
return INVOKE_THUNK(NotifyBadMessage, message, error, error_num_bytes,
|
|
options);
|
|
}
|
|
|
|
MojoResult MojoWrapPlatformHandle(const MojoPlatformHandle* platform_handle,
|
|
const MojoWrapPlatformHandleOptions* options,
|
|
MojoHandle* mojo_handle) {
|
|
return INVOKE_THUNK(WrapPlatformHandle, platform_handle, options,
|
|
mojo_handle);
|
|
}
|
|
|
|
MojoResult MojoUnwrapPlatformHandle(
|
|
MojoHandle mojo_handle,
|
|
const MojoUnwrapPlatformHandleOptions* options,
|
|
MojoPlatformHandle* platform_handle) {
|
|
return INVOKE_THUNK(UnwrapPlatformHandle, mojo_handle, options,
|
|
platform_handle);
|
|
}
|
|
|
|
MojoResult MojoWrapPlatformSharedMemoryRegion(
|
|
const struct MojoPlatformHandle* platform_handles,
|
|
uint32_t num_platform_handles,
|
|
uint64_t num_bytes,
|
|
const MojoSharedBufferGuid* guid,
|
|
MojoPlatformSharedMemoryRegionAccessMode access_mode,
|
|
const MojoWrapPlatformSharedMemoryRegionOptions* options,
|
|
MojoHandle* mojo_handle) {
|
|
return INVOKE_THUNK(WrapPlatformSharedMemoryRegion, platform_handles,
|
|
num_platform_handles, num_bytes, guid, access_mode,
|
|
options, mojo_handle);
|
|
}
|
|
|
|
MojoResult MojoUnwrapPlatformSharedMemoryRegion(
|
|
MojoHandle mojo_handle,
|
|
const MojoUnwrapPlatformSharedMemoryRegionOptions* options,
|
|
struct MojoPlatformHandle* platform_handles,
|
|
uint32_t* num_platform_handles,
|
|
uint64_t* num_bytes,
|
|
struct MojoSharedBufferGuid* guid,
|
|
MojoPlatformSharedMemoryRegionAccessMode* access_mode) {
|
|
return INVOKE_THUNK(UnwrapPlatformSharedMemoryRegion, mojo_handle, options,
|
|
platform_handles, num_platform_handles, num_bytes, guid,
|
|
access_mode);
|
|
}
|
|
|
|
MojoResult MojoCreateInvitation(const MojoCreateInvitationOptions* options,
|
|
MojoHandle* invitation_handle) {
|
|
return INVOKE_THUNK(CreateInvitation, options, invitation_handle);
|
|
}
|
|
|
|
MojoResult MojoAttachMessagePipeToInvitation(
|
|
MojoHandle invitation_handle,
|
|
const void* name,
|
|
uint32_t name_num_bytes,
|
|
const MojoAttachMessagePipeToInvitationOptions* options,
|
|
MojoHandle* message_pipe_handle) {
|
|
return INVOKE_THUNK(AttachMessagePipeToInvitation, invitation_handle, name,
|
|
name_num_bytes, options, message_pipe_handle);
|
|
}
|
|
|
|
MojoResult MojoExtractMessagePipeFromInvitation(
|
|
MojoHandle invitation_handle,
|
|
const void* name,
|
|
uint32_t name_num_bytes,
|
|
const MojoExtractMessagePipeFromInvitationOptions* options,
|
|
MojoHandle* message_pipe_handle) {
|
|
return INVOKE_THUNK(ExtractMessagePipeFromInvitation, invitation_handle, name,
|
|
name_num_bytes, options, message_pipe_handle);
|
|
}
|
|
|
|
MojoResult MojoSendInvitation(
|
|
MojoHandle invitation_handle,
|
|
const MojoPlatformProcessHandle* process_handle,
|
|
const MojoInvitationTransportEndpoint* transport_endpoint,
|
|
MojoProcessErrorHandler error_handler,
|
|
uintptr_t error_handler_context,
|
|
const MojoSendInvitationOptions* options) {
|
|
return INVOKE_THUNK(SendInvitation, invitation_handle, process_handle,
|
|
transport_endpoint, error_handler, error_handler_context,
|
|
options);
|
|
}
|
|
|
|
MojoResult MojoAcceptInvitation(
|
|
const MojoInvitationTransportEndpoint* transport_endpoint,
|
|
const MojoAcceptInvitationOptions* options,
|
|
MojoHandle* invitation_handle) {
|
|
return INVOKE_THUNK(AcceptInvitation, transport_endpoint, options,
|
|
invitation_handle);
|
|
}
|
|
|
|
MojoResult MojoSetQuota(MojoHandle handle,
|
|
MojoQuotaType type,
|
|
uint64_t limit,
|
|
const MojoSetQuotaOptions* options) {
|
|
return INVOKE_THUNK(SetQuota, handle, type, limit, options);
|
|
}
|
|
|
|
MojoResult MojoQueryQuota(MojoHandle handle,
|
|
MojoQuotaType type,
|
|
const MojoQueryQuotaOptions* options,
|
|
uint64_t* limit,
|
|
uint64_t* usage) {
|
|
return INVOKE_THUNK(QueryQuota, handle, type, options, limit, usage);
|
|
}
|
|
|
|
} // extern "C"
|
|
|
|
void MojoEmbedderSetSystemThunks(const MojoSystemThunks* thunks) {
|
|
// Assume embedders will always use matching versions of the Mojo Core and
|
|
// public APIs.
|
|
DCHECK_EQ(thunks->size, sizeof(*g_thunks));
|
|
|
|
// This should only have to check that the |g_thunks->size| is zero, but we
|
|
// have multiple Mojo Core initializations in some test suites still. For now
|
|
// we allow double calls as long as they're the same thunks as before.
|
|
DCHECK(g_thunks->size == 0 || !memcmp(&*g_thunks, thunks, sizeof(*g_thunks)))
|
|
<< "Cannot set embedder thunks after Mojo API calls have been made.";
|
|
|
|
auto writer = base::AutoWritableMemory::Create(g_thunks);
|
|
*g_thunks = *thunks;
|
|
}
|