普通文本  |  319行  |  10.19 KB

// Copyright 2015 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 <string.h>

#include <string>
#include <utility>

#include "base/logging.h"
#include "base/memory/shared_memory.h"
#include "base/strings/string_piece.h"
#include "mojo/edk/test/mojo_test_base.h"
#include "mojo/public/c/system/types.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace mojo {
namespace edk {
namespace {

using SharedBufferTest = test::MojoTestBase;

TEST_F(SharedBufferTest, CreateSharedBuffer) {
  const std::string message = "hello";
  MojoHandle h = CreateBuffer(message.size());
  WriteToBuffer(h, 0, message);
  ExpectBufferContents(h, 0, message);
}

TEST_F(SharedBufferTest, DuplicateSharedBuffer) {
  const std::string message = "hello";
  MojoHandle h = CreateBuffer(message.size());
  WriteToBuffer(h, 0, message);

  MojoHandle dupe = DuplicateBuffer(h, false);
  ExpectBufferContents(dupe, 0, message);
}

TEST_F(SharedBufferTest, PassSharedBufferLocal) {
  const std::string message = "hello";
  MojoHandle h = CreateBuffer(message.size());
  WriteToBuffer(h, 0, message);

  MojoHandle dupe = DuplicateBuffer(h, false);
  MojoHandle p0, p1;
  CreateMessagePipe(&p0, &p1);

  WriteMessageWithHandles(p0, "...", &dupe, 1);
  EXPECT_EQ("...", ReadMessageWithHandles(p1, &dupe, 1));

  ExpectBufferContents(dupe, 0, message);
}

#if !defined(OS_IOS)

// Reads a single message with a shared buffer handle, maps the buffer, copies
// the message contents into it, then exits.
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CopyToBufferClient, SharedBufferTest, h) {
  MojoHandle b;
  std::string message = ReadMessageWithHandles(h, &b, 1);
  WriteToBuffer(b, 0, message);

  EXPECT_EQ("quit", ReadMessage(h));
}

TEST_F(SharedBufferTest, PassSharedBufferCrossProcess) {
  const std::string message = "hello";
  MojoHandle b = CreateBuffer(message.size());

  RUN_CHILD_ON_PIPE(CopyToBufferClient, h)
    MojoHandle dupe = DuplicateBuffer(b, false);
    WriteMessageWithHandles(h, message, &dupe, 1);
    WriteMessage(h, "quit");
  END_CHILD()

  ExpectBufferContents(b, 0, message);
}

// Creates a new buffer, maps it, writes a message contents to it, unmaps it,
// and finally passes it back to the parent.
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateBufferClient, SharedBufferTest, h) {
  std::string message = ReadMessage(h);
  MojoHandle b = CreateBuffer(message.size());
  WriteToBuffer(b, 0, message);
  WriteMessageWithHandles(h, "have a buffer", &b, 1);

  EXPECT_EQ("quit", ReadMessage(h));
}

TEST_F(SharedBufferTest, PassSharedBufferFromChild) {
  const std::string message = "hello";
  MojoHandle b;
  RUN_CHILD_ON_PIPE(CreateBufferClient, h)
    WriteMessage(h, message);
    ReadMessageWithHandles(h, &b, 1);
    WriteMessage(h, "quit");
  END_CHILD()

  ExpectBufferContents(b, 0, message);
}

DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateAndPassBuffer, SharedBufferTest, h) {
  // Receive a pipe handle over the primordial pipe. This will be connected to
  // another child process.
  MojoHandle other_child;
  std::string message = ReadMessageWithHandles(h, &other_child, 1);

  // Create a new shared buffer.
  MojoHandle b = CreateBuffer(message.size());

  // Send a copy of the buffer to the parent and the other child.
  MojoHandle dupe = DuplicateBuffer(b, false);
  WriteMessageWithHandles(h, "", &b, 1);
  WriteMessageWithHandles(other_child, "", &dupe, 1);

  EXPECT_EQ("quit", ReadMessage(h));
}

DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceiveAndEditBuffer, SharedBufferTest, h) {
  // Receive a pipe handle over the primordial pipe. This will be connected to
  // another child process (running CreateAndPassBuffer).
  MojoHandle other_child;
  std::string message = ReadMessageWithHandles(h, &other_child, 1);

  // Receive a shared buffer from the other child.
  MojoHandle b;
  ReadMessageWithHandles(other_child, &b, 1);

  // Write the message from the parent into the buffer and exit.
  WriteToBuffer(b, 0, message);
  EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
  EXPECT_EQ("quit", ReadMessage(h));
}

TEST_F(SharedBufferTest, PassSharedBufferFromChildToChild) {
  const std::string message = "hello";
  MojoHandle p0, p1;
  CreateMessagePipe(&p0, &p1);

  MojoHandle b;
  RUN_CHILD_ON_PIPE(CreateAndPassBuffer, h0)
    RUN_CHILD_ON_PIPE(ReceiveAndEditBuffer, h1)
      // Send one end of the pipe to each child. The first child will create
      // and pass a buffer to the second child and back to us. The second child
      // will write our message into the buffer.
      WriteMessageWithHandles(h0, message, &p0, 1);
      WriteMessageWithHandles(h1, message, &p1, 1);

      // Receive the buffer back from the first child.
      ReadMessageWithHandles(h0, &b, 1);

      WriteMessage(h1, "quit");
    END_CHILD()
    WriteMessage(h0, "quit");
  END_CHILD()

  // The second child should have written this message.
  ExpectBufferContents(b, 0, message);
}

DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateAndPassBufferParent, SharedBufferTest,
                                  parent) {
  RUN_CHILD_ON_PIPE(CreateAndPassBuffer, child)
    // Read a pipe from the parent and forward it to our child.
    MojoHandle pipe;
    std::string message = ReadMessageWithHandles(parent, &pipe, 1);

    WriteMessageWithHandles(child, message, &pipe, 1);

    // Read a buffer handle from the child and pass it back to the parent.
    MojoHandle buffer;
    EXPECT_EQ("", ReadMessageWithHandles(child, &buffer, 1));
    WriteMessageWithHandles(parent, "", &buffer, 1);

    EXPECT_EQ("quit", ReadMessage(parent));
    WriteMessage(child, "quit");
  END_CHILD()
}

DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceiveAndEditBufferParent, SharedBufferTest,
                                  parent) {
  RUN_CHILD_ON_PIPE(ReceiveAndEditBuffer, child)
    // Read a pipe from the parent and forward it to our child.
    MojoHandle pipe;
    std::string message = ReadMessageWithHandles(parent, &pipe, 1);
    WriteMessageWithHandles(child, message, &pipe, 1);

    EXPECT_EQ("quit", ReadMessage(parent));
    WriteMessage(child, "quit");
  END_CHILD()
}

#if defined(OS_ANDROID) || defined(OS_MACOSX)
// Android multi-process tests are not executing the new process. This is flaky.
// Passing shared memory handles between cousins is not currently supported on
// OSX.
#define MAYBE_PassHandleBetweenCousins DISABLED_PassHandleBetweenCousins
#else
#define MAYBE_PassHandleBetweenCousins PassHandleBetweenCousins
#endif
TEST_F(SharedBufferTest, MAYBE_PassHandleBetweenCousins) {
  const std::string message = "hello";
  MojoHandle p0, p1;
  CreateMessagePipe(&p0, &p1);

  // Spawn two children who will each spawn their own child. Make sure the
  // grandchildren (cousins to each other) can pass platform handles.
  MojoHandle b;
  RUN_CHILD_ON_PIPE(CreateAndPassBufferParent, child1)
    RUN_CHILD_ON_PIPE(ReceiveAndEditBufferParent, child2)
      MojoHandle pipe[2];
      CreateMessagePipe(&pipe[0], &pipe[1]);

      WriteMessageWithHandles(child1, message, &pipe[0], 1);
      WriteMessageWithHandles(child2, message, &pipe[1], 1);

      // Receive the buffer back from the first child.
      ReadMessageWithHandles(child1, &b, 1);

      WriteMessage(child2, "quit");
    END_CHILD()
    WriteMessage(child1, "quit");
  END_CHILD()

  // The second grandchild should have written this message.
  ExpectBufferContents(b, 0, message);
}

DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadAndMapWriteSharedBuffer,
                                  SharedBufferTest, h) {
  // Receive the shared buffer.
  MojoHandle b;
  EXPECT_EQ("hello", ReadMessageWithHandles(h, &b, 1));

  // Read from the bufer.
  ExpectBufferContents(b, 0, "hello");

  // Extract the shared memory handle and try to map it writable.
  base::SharedMemoryHandle shm_handle;
  bool read_only = false;
  ASSERT_EQ(MOJO_RESULT_OK,
            PassSharedMemoryHandle(b, &shm_handle, nullptr, &read_only));
  base::SharedMemory shared_memory(shm_handle, false);
  EXPECT_TRUE(read_only);
  EXPECT_FALSE(shared_memory.Map(1234));

  EXPECT_EQ("quit", ReadMessage(h));
  WriteMessage(h, "ok");
}

#if defined(OS_ANDROID)
// Android multi-process tests are not executing the new process. This is flaky.
#define MAYBE_CreateAndPassReadOnlyBuffer DISABLED_CreateAndPassReadOnlyBuffer
#else
#define MAYBE_CreateAndPassReadOnlyBuffer CreateAndPassReadOnlyBuffer
#endif
TEST_F(SharedBufferTest, MAYBE_CreateAndPassReadOnlyBuffer) {
  RUN_CHILD_ON_PIPE(ReadAndMapWriteSharedBuffer, h)
    // Create a new shared buffer.
    MojoHandle b = CreateBuffer(1234);
    WriteToBuffer(b, 0, "hello");

    // Send a read-only copy of the buffer to the child.
    MojoHandle dupe = DuplicateBuffer(b, true /* read_only */);
    WriteMessageWithHandles(h, "hello", &dupe, 1);

    WriteMessage(h, "quit");
    EXPECT_EQ("ok", ReadMessage(h));
  END_CHILD()
}

DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateAndPassReadOnlyBuffer,
                                  SharedBufferTest, h) {
  // Create a new shared buffer.
  MojoHandle b = CreateBuffer(1234);
  WriteToBuffer(b, 0, "hello");

  // Send a read-only copy of the buffer to the parent.
  MojoHandle dupe = DuplicateBuffer(b, true /* read_only */);
  WriteMessageWithHandles(h, "", &dupe, 1);

  EXPECT_EQ("quit", ReadMessage(h));
  WriteMessage(h, "ok");
}

#if defined(OS_ANDROID)
// Android multi-process tests are not executing the new process. This is flaky.
#define MAYBE_CreateAndPassFromChildReadOnlyBuffer \
    DISABLED_CreateAndPassFromChildReadOnlyBuffer
#else
#define MAYBE_CreateAndPassFromChildReadOnlyBuffer \
    CreateAndPassFromChildReadOnlyBuffer
#endif
TEST_F(SharedBufferTest, MAYBE_CreateAndPassFromChildReadOnlyBuffer) {
  RUN_CHILD_ON_PIPE(CreateAndPassReadOnlyBuffer, h)
    MojoHandle b;
    EXPECT_EQ("", ReadMessageWithHandles(h, &b, 1));
    ExpectBufferContents(b, 0, "hello");

    // Extract the shared memory handle and try to map it writable.
    base::SharedMemoryHandle shm_handle;
    bool read_only = false;
    ASSERT_EQ(MOJO_RESULT_OK,
              PassSharedMemoryHandle(b, &shm_handle, nullptr, &read_only));
    base::SharedMemory shared_memory(shm_handle, false);
    EXPECT_TRUE(read_only);
    EXPECT_FALSE(shared_memory.Map(1234));

    WriteMessage(h, "quit");
    EXPECT_EQ("ok", ReadMessage(h));
  END_CHILD()
}

#endif  // !defined(OS_IOS)

}  // namespace
}  // namespace edk
}  // namespace mojo