910e62b5创建于 1月15日历史提交
// Copyright 2014 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/core/embedder/embedder.h"

#include <stdint.h>

#include <optional>
#include <string>
#include <utility>

#include "base/check.h"
#include "base/feature_list.h"
#include "base/memory/ref_counted.h"
#include "base/notreached.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_ipcz.h"
#include "mojo/core/embedder/features.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/public/c/system/thunks.h"

#if BUILDFLAG(MOJO_SUPPORT_LEGACY_CORE)
#include <atomic>

#include "base/environment.h"
#include "mojo/core/core.h"
#include "mojo/core/entrypoints.h"
#include "mojo/core/node_controller.h"
#endif

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
#include "mojo/core/channel_linux.h"
#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||
        // BUILDFLAG(IS_ANDROID)

namespace mojo::core {

namespace {

#if BUILDFLAG(MOJO_SUPPORT_LEGACY_CORE)
#if BUILDFLAG(IS_CHROMEOS) && !defined(ENABLE_IPCZ_ON_CHROMEOS)
std::atomic<bool> g_mojo_ipcz_enabled{false};
#else
// Default to enabled even if InitFeatures() is never called.
std::atomic<bool> g_mojo_ipcz_enabled{true};
#endif

bool g_mojo_ipcz_force_disabled = false;

std::optional<std::string> GetMojoIpczEnvVar() {
  auto env = base::Environment::Create();
  return env->GetVar("MOJO_IPCZ");
}

// Allows MojoIpcz to be forcibly enabled if and only if MOJO_IPCZ=1 in the
// environment. Note that any other value (or absence) has no influence on
// whether or not MojoIpcz is enabled.
bool IsMojoIpczForceEnabledByEnvironment() {
  static bool force_enabled = GetMojoIpczEnvVar() == "1";
  return force_enabled;
}
#endif  // BUILDFLAG(MOJO_SUPPORT_LEGACY_CORE)

bool g_enable_memv2 = false;

}  // namespace

// InitFeatures will be called as soon as the base::FeatureList is initialized.
void InitFeatures() {
  CHECK(base::FeatureList::GetInstance());

#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(MOJO_USE_APPLE_CHANNEL)
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
  bool shared_mem_enabled = base::FeatureList::IsEnabled(kMojoUseEventFd);
  int num_pages = kMojoUseEventFdPages.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));
#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||
        // BUILDFLAG(IS_ANDROID)
#endif  // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)

  Channel::set_use_trivial_messages(
      base::FeatureList::IsEnabled(kMojoInlineMessagePayloads));

#if BUILDFLAG(MOJO_SUPPORT_LEGACY_CORE)
  if (base::FeatureList::IsEnabled(kMojoIpcz)) {
    EnableMojoIpcz();
  } else {
    g_mojo_ipcz_enabled.store(false, std::memory_order_release);
  }
#endif  // !BUILDFLAG(IS_ANDROID)

  g_enable_memv2 = base::FeatureList::IsEnabled(kMojoIpczMemV2);
}

void EnableMojoIpcz() {
#if BUILDFLAG(MOJO_SUPPORT_LEGACY_CORE)
  g_mojo_ipcz_enabled.store(true, std::memory_order_release);
#endif
}

void Init(const Configuration& configuration) {
  internal::g_configuration = configuration;

#if BUILDFLAG(MOJO_SUPPORT_LEGACY_CORE)
  if (configuration.disable_ipcz) {
    // Allow the caller to override MojoIpcz even when enabled by Feature or
    // environment.
    g_mojo_ipcz_force_disabled = true;
  }
#else
  CHECK(!configuration.disable_ipcz);
#endif

  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,
        .enable_memv2 = g_enable_memv2,
    }));
    MojoEmbedderSetSystemThunks(GetMojoIpczImpl());
  } else {
#if BUILDFLAG(MOJO_SUPPORT_LEGACY_CORE)
    InitializeCore();
    MojoEmbedderSetSystemThunks(&GetSystemThunks());
#else
    NOTREACHED();
#endif
  }
}

void Init() {
  Init(Configuration());
}

void ShutDown() {
  if (IsMojoIpczEnabled()) {
    DestroyIpczNodeForProcess();
  } else {
#if BUILDFLAG(MOJO_SUPPORT_LEGACY_CORE)
    ShutDownCore();
#else
    NOTREACHED();
#endif
  }
}

scoped_refptr<base::SingleThreadTaskRunner> GetIOTaskRunner() {
  if (IsMojoIpczEnabled()) {
    return ipcz_driver::Transport::GetIOTaskRunner();
  } else {
#if BUILDFLAG(MOJO_SUPPORT_LEGACY_CORE)
    return Core::Get()->GetNodeController()->io_task_runner();
#else
    NOTREACHED();
#endif
  }
}

bool IsMojoIpczEnabled() {
#if !BUILDFLAG(MOJO_SUPPORT_LEGACY_CORE)
  return true;
#else
  // Because Mojo and FeatureList are both brought up early in many binaries, it
  // can be tricky to ensure there aren't races that would lead to two different
  // Mojo implementations being selected at different points throughout the
  // process's lifetime. We cache the result of the first call to this function
  // and DCHECK that every subsequent call produces the same result. Note that
  // setting `disable_ipcz` in the Mojo config overrides both the Feature value
  // and the environment variable if set.
  const bool enabled = (g_mojo_ipcz_enabled.load(std::memory_order_acquire) ||
                        IsMojoIpczForceEnabledByEnvironment()) &&
                       !g_mojo_ipcz_force_disabled;
  static bool enabled_on_first_call = enabled;
  DCHECK_EQ(enabled, enabled_on_first_call);
  return enabled;
#endif
}

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));
}

}  // namespace mojo::core