#include <stddef.h>
#include "base/at_exit.h"
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/debug/stack_trace.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/message_loop/message_pump_type.h"
#include "base/metrics/field_trial.h"
#include "base/no_destructor.h"
#include "base/rand_util.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "mojo/core/configuration.h"
#include "mojo/core/core.h"
#include "mojo/core/entrypoints.h"
#include "mojo/public/c/system/core.h"
#include "mojo/public/c/system/macros.h"
#include "mojo/public/c/system/thunks.h"
namespace {
class IPCSupport {
public:
IPCSupport() : ipc_thread_("Mojo IPC") {
base::Thread::Options options(base::MessagePumpType::IO, 0);
ipc_thread_.StartWithOptions(std::move(options));
mojo::core::Core::Get()->SetIOTaskRunner(ipc_thread_.task_runner());
}
IPCSupport(const IPCSupport&) = delete;
IPCSupport& operator=(const IPCSupport&) = delete;
~IPCSupport() {
base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
mojo::core::Core::Get()->RequestShutdown(
base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(&wait)));
wait.Wait();
}
private:
#if !defined(COMPONENT_BUILD)
base::AtExitManager at_exit_manager_;
#endif
base::Thread ipc_thread_;
};
std::unique_ptr<IPCSupport>& GetIPCSupport() {
static base::NoDestructor<std::unique_ptr<IPCSupport>> state;
return *state;
}
class GlobalStateInitializer {
public:
GlobalStateInitializer() = default;
bool Initialize(int argc, const char* const* argv) {
if (initialized_)
return false;
initialized_ = true;
#if !defined(COMPONENT_BUILD)
base::CommandLine::Init(argc, argv);
logging::LoggingSettings settings;
settings.logging_dest =
logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR;
logging::InitLogging(settings);
logging::SetLogItems(true,
true,
true,
true);
#if !defined(OFFICIAL_BUILD) && !BUILDFLAG(IS_WIN)
base::debug::EnableInProcessStackDumping();
#endif
#if BUILDFLAG(IS_POSIX)
base::RandUint64();
#endif
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
field_trial_list_ = std::make_unique<base::FieldTrialList>();
base::FeatureList::InitializeInstance(
command_line->GetSwitchValueASCII(switches::kEnableFeatures),
command_line->GetSwitchValueASCII(switches::kDisableFeatures));
#endif
return true;
}
private:
bool initialized_ = false;
std::unique_ptr<base::FieldTrialList> field_trial_list_;
};
}
extern "C" {
namespace {
MojoResult InitializeImpl(const struct MojoInitializeOptions* options) {
std::unique_ptr<IPCSupport>& ipc_support = GetIPCSupport();
if (ipc_support) {
return MOJO_RESULT_FAILED_PRECONDITION;
}
const bool should_initialize_ipc_support =
!options || ((options->flags & MOJO_INITIALIZE_FLAG_LOAD_ONLY) == 0);
int argc = 0;
const char* const* argv = nullptr;
if (options && MOJO_IS_STRUCT_FIELD_PRESENT(options, argv)) {
argc = options->argc;
argv = options->argv;
}
static GlobalStateInitializer global_state_initializer;
const bool was_global_state_already_initialized =
!global_state_initializer.Initialize(argc, argv);
if (!should_initialize_ipc_support) {
if (was_global_state_already_initialized)
return MOJO_RESULT_ALREADY_EXISTS;
else
return MOJO_RESULT_OK;
}
DCHECK(!mojo::core::Core::Get());
mojo::core::Configuration config;
config.is_broker_process =
options && options->flags & MOJO_INITIALIZE_FLAG_AS_BROKER;
config.force_direct_shared_memory_allocation =
options && options->flags &
MOJO_INITIALIZE_FLAG_FORCE_DIRECT_SHARED_MEMORY_ALLOCATION;
mojo::core::internal::g_configuration = config;
mojo::core::InitializeCore();
ipc_support = std::make_unique<IPCSupport>();
return MOJO_RESULT_OK;
}
MojoResult ShutdownImpl(const struct MojoShutdownOptions* options) {
if (options && options->struct_size < sizeof(*options))
return MOJO_RESULT_INVALID_ARGUMENT;
std::unique_ptr<IPCSupport>& ipc_support = GetIPCSupport();
if (!ipc_support)
return MOJO_RESULT_FAILED_PRECONDITION;
ipc_support.reset();
return MOJO_RESULT_OK;
}
MojoSystemThunks2 g_thunks = {0};
}
#if defined(WIN32)
#define EXPORT_FROM_MOJO_CORE __declspec(dllexport)
#else
#define EXPORT_FROM_MOJO_CORE __attribute__((visibility("default")))
#endif
EXPORT_FROM_MOJO_CORE void MojoGetSystemThunks(MojoSystemThunks2* thunks) {
if (!g_thunks.size) {
g_thunks = mojo::core::GetSystemThunks();
g_thunks.Initialize = InitializeImpl;
g_thunks.Shutdown = ShutdownImpl;
}
CHECK_GE(thunks->size, offsetof(MojoSystemThunks2, SetQuota));
if (thunks->size > g_thunks.size)
thunks->size = g_thunks.size;
memcpy(thunks, &g_thunks, thunks->size);
}
}