chromium/mojo/core/embedder_unittest.cc

// 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.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "mojo/core/embedder/embedder.h"

#include <stddef.h>
#include <stdint.h>
#include <string.h>

#include <utility>

#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/files/file.h"
#include "base/functional/bind.h"
#include "base/memory/ptr_util.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "base/memory/writable_shared_memory_region.h"
#include "base/notreached.h"
#include "base/path_service.h"
#include "base/rand_util.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/test_timeouts.h"
#include "build/build_config.h"
#include "mojo/buildflags.h"
#include "mojo/core/embedder/embedder.h"
#include "mojo/core/ipcz_driver/shared_buffer.h"
#include "mojo/core/test/mojo_test_base.h"
#include "mojo/public/c/system/core.h"
#include "mojo/public/cpp/system/handle.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "mojo/public/cpp/system/wait.h"
#include "testing/gtest/include/gtest/gtest.h"

#if BUILDFLAG(MOJO_SUPPORT_LEGACY_CORE)
#include "mojo/core/core.h"
#include "mojo/core/shared_buffer_dispatcher.h"
#endif

namespace mojo::core {
namespace {

template <typename T>
MojoResult CreateSharedBufferFromRegion(T&& region, MojoHandle* handle) {}

template <typename T>
MojoResult ExtractRegionFromSharedBuffer(MojoHandle handle, T* region) {}

// The multiprocess tests that use these don't compile on iOS.
#if !BUILDFLAG(IS_IOS)
const char kHelloWorld[] =;
const char kByeWorld[] =;
#endif

EmbedderTest;

TEST_F(EmbedderTest, ChannelBasic) {}

// Verifies that a MP with pending messages to be written can be sent and the
// pending messages aren't dropped.
TEST_F(EmbedderTest, SendMessagePipeWithWriteQueue) {}

TEST_F(EmbedderTest, ChannelsHandlePassing) {}

// The sequence of messages sent is:
//       server_mp   client_mp   mp0         mp1         mp2         mp3
//   1.  "hello"
//   2.              "world!"
//   3.                          "FOO"
//   4.  "Bar"+mp1
//   5.  (close)
//   6.              (close)
//   7.                                                              "baz"
//   8.                                                              (closed)
//   9.                                      "quux"+mp2
//  10.                          (close)
//  11.                                      (wait/cl.)
//  12.                                                  (wait/cl.)

#if !BUILDFLAG(IS_IOS)

TEST_F(EmbedderTest, MultiprocessChannels) {}

DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessChannelsClient,
                                  EmbedderTest,
                                  client_mp) {}

TEST_F(EmbedderTest, MultiprocessBaseSharedMemory) {}

DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessSharedMemoryClient,
                                  EmbedderTest,
                                  client_mp) {}

#if BUILDFLAG(IS_MAC)

enum class HandleType {
  POSIX,
  MACH,
};

const HandleType kTestHandleTypes[] = {
    HandleType::MACH, HandleType::POSIX, HandleType::POSIX, HandleType::MACH,
};

// Test that we can mix file descriptors and mach port handles.
TEST_F(EmbedderTest, MultiprocessMixMachAndFds) {
  const size_t kShmSize = 1234;
  RunTestClient("MultiprocessMixMachAndFdsClient", [&](MojoHandle server_mp) {
    // 1. Create fds or Mach objects and mojo handles from them.
    MojoHandle platform_handles[std::size(kTestHandleTypes)];
    for (size_t i = 0; i < std::size(kTestHandleTypes); i++) {
      const auto type = kTestHandleTypes[i];
      PlatformHandle scoped_handle;
      if (type == HandleType::POSIX) {
        // The easiest source of fds is opening /dev/null.
        base::File file(base::FilePath("/dev/null"),
                        base::File::FLAG_OPEN | base::File::FLAG_WRITE);
        ASSERT_TRUE(file.IsValid());
        scoped_handle = PlatformHandle(base::ScopedFD(file.TakePlatformFile()));
        ASSERT_TRUE(scoped_handle.is_valid_fd());
      } else {
        auto shared_memory = base::UnsafeSharedMemoryRegion::Create(kShmSize);
        ASSERT_TRUE(shared_memory.IsValid());
        auto shm_handle =
            base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
                std::move(shared_memory))
                .PassPlatformHandle();
        scoped_handle = PlatformHandle(std::move(shm_handle));
        ASSERT_TRUE(scoped_handle.is_valid_mach_port());
      }
      platform_handles[i] =
          WrapPlatformHandle(std::move(scoped_handle)).release().value();
    }

    // 2. Send all the handles to the child.
    WriteMessageWithHandles(server_mp, "hello", platform_handles,
                            std::size(kTestHandleTypes));

    // 3. Read a message from |server_mp|.
    EXPECT_EQ("bye", ReadMessage(server_mp));
  });
}

DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessMixMachAndFdsClient,
                                  EmbedderTest,
                                  client_mp) {
  const int kNumHandles = std::size(kTestHandleTypes);
  MojoHandle platform_handles[kNumHandles];

  // 1. Read from |client_mp|, which should have a message containing
  // |kNumHandles| handles.
  EXPECT_EQ("hello",
            ReadMessageWithHandles(client_mp, platform_handles, kNumHandles));

  // 2. Extract each handle, and verify the type.
  for (int i = 0; i < kNumHandles; i++) {
    const auto type = kTestHandleTypes[i];
    PlatformHandle scoped_handle =
        UnwrapPlatformHandle(ScopedHandle(Handle(platform_handles[i])));
    if (type == HandleType::POSIX) {
      EXPECT_TRUE(scoped_handle.is_valid_fd());
    } else {
      EXPECT_TRUE(scoped_handle.is_valid_mach_port());
    }
  }

  // 3. Say bye!
  WriteMessage(client_mp, "bye");
  ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp));
}

#endif  // BUILDFLAG(IS_MAC)

#endif  // !BUILDFLAG(IS_IOS)

}  // namespace
}  // namespace mojo::core