#include "mojo/core/embedder/embedder.h"
#include <stdint.h>
#include <atomic>
#include <utility>
#include "base/check.h"
#include "base/feature_list.h"
#include "base/memory/ref_counted.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/task_runner.h"
#include "build/build_config.h"
#include "mojo/buildflags.h"
#include "mojo/core/channel.h"
#include "mojo/core/configuration.h"
#include "mojo/core/core.h"
#include "mojo/core/core_ipcz.h"
#include "mojo/core/embedder/features.h"
#include "mojo/core/entrypoints.h"
#include "mojo/core/ipcz_api.h"
#include "mojo/core/ipcz_driver/base_shared_memory_service.h"
#include "mojo/core/ipcz_driver/driver.h"
#include "mojo/core/ipcz_driver/transport.h"
#include "mojo/core/node_controller.h"
#include "mojo/public/c/system/thunks.h"
#if !BUILDFLAG(IS_NACL)
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
#include "mojo/core/channel_linux.h"
#endif
#endif
namespace mojo::core {
namespace {
#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
std::atomic<bool> g_mojo_ipcz_enabled{false};
#else
std::atomic<bool> g_mojo_ipcz_enabled{true};
#endif
}
void InitFeatures() {
CHECK(base::FeatureList::GetInstance());
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL) && \
!BUILDFLAG(MOJO_USE_APPLE_CHANNEL)
Channel::set_posix_use_writev(
base::FeatureList::IsEnabled(kMojoPosixUseWritev));
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
bool shared_mem_enabled =
base::FeatureList::IsEnabled(kMojoLinuxChannelSharedMem);
bool use_zero_on_wake = kMojoLinuxChannelSharedMemEfdZeroOnWake.Get();
int num_pages = kMojoLinuxChannelSharedMemPages.Get();
if (num_pages < 0) {
num_pages = 4;
} else if (num_pages > 128) {
num_pages = 128;
}
ChannelLinux::SetSharedMemParameters(shared_mem_enabled,
static_cast<unsigned int>(num_pages),
use_zero_on_wake);
#endif
#endif
Channel::set_use_trivial_messages(
base::FeatureList::IsEnabled(kMojoInlineMessagePayloads));
if (base::FeatureList::IsEnabled(kMojoIpcz)) {
EnableMojoIpcz();
} else {
g_mojo_ipcz_enabled.store(false, std::memory_order_release);
}
}
void EnableMojoIpcz() {
g_mojo_ipcz_enabled.store(true, std::memory_order_release);
}
void Init(const Configuration& configuration) {
internal::g_configuration = configuration;
if (configuration.disable_ipcz) {
g_mojo_ipcz_enabled.store(false, std::memory_order_release);
}
if (IsMojoIpczEnabled()) {
CHECK(InitializeIpczNodeForProcess({
.is_broker = configuration.is_broker_process,
.use_local_shared_memory_allocation =
configuration.is_broker_process ||
configuration.force_direct_shared_memory_allocation,
}));
MojoEmbedderSetSystemThunks(GetMojoIpczImpl());
} else {
InitializeCore();
MojoEmbedderSetSystemThunks(&GetSystemThunks());
}
}
void Init() {
Init(Configuration());
}
void ShutDown() {
if (IsMojoIpczEnabled()) {
DestroyIpczNodeForProcess();
} else {
ShutDownCore();
}
}
scoped_refptr<base::SingleThreadTaskRunner> GetIOTaskRunner() {
if (IsMojoIpczEnabled()) {
return ipcz_driver::Transport::GetIOTaskRunner();
} else {
return Core::Get()->GetNodeController()->io_task_runner();
}
}
bool IsMojoIpczEnabled() {
static bool enabled = g_mojo_ipcz_enabled.load(std::memory_order_acquire);
DCHECK_EQ(enabled, g_mojo_ipcz_enabled.load(std::memory_order_acquire));
return enabled;
}
void InstallMojoIpczBaseSharedMemoryHooks() {
DCHECK(IsMojoIpczEnabled());
ipcz_driver::BaseSharedMemoryService::InstallHooks();
}
const IpczAPI& GetIpczAPIForMojo() {
return GetIpczAPI();
}
const IpczDriver& GetIpczDriverForMojo() {
return ipcz_driver::kDriver;
}
IpczDriverHandle CreateIpczTransportFromEndpoint(
mojo::PlatformChannelEndpoint endpoint,
const TransportEndpointTypes& endpoint_types,
base::Process remote_process) {
auto transport = ipcz_driver::Transport::Create(
{
.source = endpoint_types.local_is_broker
? ipcz_driver::Transport::kBroker
: ipcz_driver::Transport::kNonBroker,
.destination = endpoint_types.remote_is_broker
? ipcz_driver::Transport::kBroker
: ipcz_driver::Transport::kNonBroker,
},
std::move(endpoint), std::move(remote_process));
return ipcz_driver::ObjectBase::ReleaseAsHandle(std::move(transport));
}
}