Home | History | Annotate | Download | only in core
      1 // Copyright 2016 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <stdint.h>
      6 #include <string.h>
      7 
      8 #include <algorithm>
      9 #include <string>
     10 #include <vector>
     11 
     12 #include "base/files/file.h"
     13 #include "base/files/file_util.h"
     14 #include "base/memory/shared_memory.h"
     15 #include "base/process/process_handle.h"
     16 #include "build/build_config.h"
     17 #include "mojo/core/test/mojo_test_base.h"
     18 #include "mojo/public/c/system/platform_handle.h"
     19 #include "mojo/public/cpp/system/message_pipe.h"
     20 #include "testing/gtest/include/gtest/gtest.h"
     21 
     22 #if defined(OS_WIN)
     23 #include <windows.h>
     24 #endif
     25 
     26 #if defined(OS_WIN)
     27 #define SIMPLE_PLATFORM_HANDLE_TYPE MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE
     28 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
     29 #define SIMPLE_PLATFORM_HANDLE_TYPE MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR
     30 #endif
     31 
     32 #if defined(OS_FUCHSIA)
     33 #define SHARED_BUFFER_PLATFORM_HANDLE_TYPE \
     34   MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE
     35 #elif defined(OS_MACOSX) && !defined(OS_IOS)
     36 #define SHARED_BUFFER_PLATFORM_HANDLE_TYPE MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT
     37 #elif defined(OS_WIN) || defined(OS_POSIX)
     38 #define SHARED_BUFFER_PLATFORM_HANDLE_TYPE SIMPLE_PLATFORM_HANDLE_TYPE
     39 #endif
     40 
     41 uint64_t PlatformHandleValueFromPlatformFile(base::PlatformFile file) {
     42 #if defined(OS_WIN)
     43   return reinterpret_cast<uint64_t>(file);
     44 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
     45   return static_cast<uint64_t>(file);
     46 #endif
     47 }
     48 
     49 base::PlatformFile PlatformFileFromPlatformHandleValue(uint64_t value) {
     50 #if defined(OS_WIN)
     51   return reinterpret_cast<base::PlatformFile>(value);
     52 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
     53   return static_cast<base::PlatformFile>(value);
     54 #endif
     55 }
     56 
     57 namespace mojo {
     58 namespace core {
     59 namespace {
     60 
     61 using PlatformWrapperTest = test::MojoTestBase;
     62 
     63 TEST_F(PlatformWrapperTest, WrapPlatformHandle) {
     64   // Create a temporary file and write a message to it.
     65   base::FilePath temp_file_path;
     66   ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path));
     67   const std::string kMessage = "Hello, world!";
     68   EXPECT_EQ(base::WriteFile(temp_file_path, kMessage.data(),
     69                             static_cast<int>(kMessage.size())),
     70             static_cast<int>(kMessage.size()));
     71 
     72   RunTestClient("ReadPlatformFile", [&](MojoHandle h) {
     73     // Open the temporary file for reading, wrap its handle, and send it to
     74     // the child along with the expected message to be read.
     75     base::File file(temp_file_path,
     76                     base::File::FLAG_OPEN | base::File::FLAG_READ);
     77     EXPECT_TRUE(file.IsValid());
     78 
     79     MojoHandle wrapped_handle;
     80     MojoPlatformHandle os_file;
     81     os_file.struct_size = sizeof(MojoPlatformHandle);
     82     os_file.type = SIMPLE_PLATFORM_HANDLE_TYPE;
     83     os_file.value =
     84         PlatformHandleValueFromPlatformFile(file.TakePlatformFile());
     85     EXPECT_EQ(MOJO_RESULT_OK,
     86               MojoWrapPlatformHandle(&os_file, nullptr, &wrapped_handle));
     87 
     88     WriteMessageWithHandles(h, kMessage, &wrapped_handle, 1);
     89   });
     90 
     91   base::DeleteFile(temp_file_path, false);
     92 }
     93 
     94 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadPlatformFile, PlatformWrapperTest, h) {
     95   // Read a message and a wrapped file handle; unwrap the handle.
     96   MojoHandle wrapped_handle;
     97   std::string message = ReadMessageWithHandles(h, &wrapped_handle, 1);
     98 
     99   MojoPlatformHandle platform_handle;
    100   platform_handle.struct_size = sizeof(MojoPlatformHandle);
    101   ASSERT_EQ(MOJO_RESULT_OK, MojoUnwrapPlatformHandle(wrapped_handle, nullptr,
    102                                                      &platform_handle));
    103   EXPECT_EQ(SIMPLE_PLATFORM_HANDLE_TYPE, platform_handle.type);
    104   base::File file(PlatformFileFromPlatformHandleValue(platform_handle.value));
    105 
    106   // Expect to read the same message from the file.
    107   std::vector<char> data(message.size());
    108   EXPECT_EQ(file.ReadAtCurrentPos(data.data(), static_cast<int>(data.size())),
    109             static_cast<int>(data.size()));
    110   EXPECT_TRUE(std::equal(message.begin(), message.end(), data.begin()));
    111 }
    112 
    113 TEST_F(PlatformWrapperTest, WrapPlatformSharedMemoryRegion) {
    114   // Allocate a new platform shared buffer and write a message into it.
    115   const std::string kMessage = "Hello, world!";
    116   base::SharedMemory buffer;
    117   buffer.CreateAndMapAnonymous(kMessage.size());
    118   CHECK(buffer.memory());
    119   memcpy(buffer.memory(), kMessage.data(), kMessage.size());
    120 
    121   RunTestClient("ReadPlatformSharedBuffer", [&](MojoHandle h) {
    122     // Wrap the shared memory handle and send it to the child along with the
    123     // expected message.
    124     base::SharedMemoryHandle memory_handle =
    125         base::SharedMemory::DuplicateHandle(buffer.handle());
    126     MojoPlatformHandle os_buffer;
    127     os_buffer.struct_size = sizeof(MojoPlatformHandle);
    128     os_buffer.type = SHARED_BUFFER_PLATFORM_HANDLE_TYPE;
    129 #if defined(OS_WIN)
    130     os_buffer.value = reinterpret_cast<uint64_t>(memory_handle.GetHandle());
    131 #elif defined(OS_MACOSX) && !defined(OS_IOS)
    132     os_buffer.value = static_cast<uint64_t>(memory_handle.GetMemoryObject());
    133 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
    134     os_buffer.value = static_cast<uint64_t>(memory_handle.GetHandle());
    135 #else
    136 #error Unsupported platform
    137 #endif
    138 
    139     MojoSharedBufferGuid mojo_guid;
    140     base::UnguessableToken guid = memory_handle.GetGUID();
    141     mojo_guid.high = guid.GetHighForSerialization();
    142     mojo_guid.low = guid.GetLowForSerialization();
    143 
    144     MojoHandle wrapped_handle;
    145     ASSERT_EQ(MOJO_RESULT_OK,
    146               MojoWrapPlatformSharedMemoryRegion(
    147                   &os_buffer, 1, kMessage.size(), &mojo_guid,
    148                   MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE,
    149                   nullptr, &wrapped_handle));
    150     WriteMessageWithHandles(h, kMessage, &wrapped_handle, 1);
    151 
    152     // As a sanity check, send the GUID explicitly in a second message. We'll
    153     // verify that the deserialized buffer handle holds the same GUID on the
    154     // receiving end.
    155     WriteMessageRaw(MessagePipeHandle(h), &mojo_guid, sizeof(mojo_guid),
    156                     nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE);
    157   });
    158 }
    159 
    160 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadPlatformSharedBuffer,
    161                                   PlatformWrapperTest,
    162                                   h) {
    163   // Read a message and a wrapped shared buffer handle.
    164   MojoHandle wrapped_handle;
    165   std::string message = ReadMessageWithHandles(h, &wrapped_handle, 1);
    166 
    167   // Check the message in the buffer
    168   ExpectBufferContents(wrapped_handle, 0, message);
    169 
    170   // Now unwrap the buffer and verify that the base::SharedMemoryHandle also
    171   // works as expected.
    172   MojoPlatformHandle os_buffer;
    173   os_buffer.struct_size = sizeof(MojoPlatformHandle);
    174   uint32_t num_handles = 1;
    175   uint64_t size;
    176   MojoSharedBufferGuid mojo_guid;
    177   MojoPlatformSharedMemoryRegionAccessMode access_mode;
    178   ASSERT_EQ(MOJO_RESULT_OK, MojoUnwrapPlatformSharedMemoryRegion(
    179                                 wrapped_handle, nullptr, &os_buffer,
    180                                 &num_handles, &size, &mojo_guid, &access_mode));
    181   EXPECT_EQ(MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE, access_mode);
    182 
    183   base::UnguessableToken guid =
    184       base::UnguessableToken::Deserialize(mojo_guid.high, mojo_guid.low);
    185 #if defined(OS_WIN)
    186   ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE, os_buffer.type);
    187   base::SharedMemoryHandle memory_handle(
    188       reinterpret_cast<HANDLE>(os_buffer.value), size, guid);
    189 #elif defined(OS_FUCHSIA)
    190   ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE, os_buffer.type);
    191   base::SharedMemoryHandle memory_handle(
    192       static_cast<zx_handle_t>(os_buffer.value), size, guid);
    193 #elif defined(OS_MACOSX) && !defined(OS_IOS)
    194   ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT, os_buffer.type);
    195   base::SharedMemoryHandle memory_handle(
    196       static_cast<mach_port_t>(os_buffer.value), size, guid);
    197 #elif defined(OS_POSIX)
    198   ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR, os_buffer.type);
    199   base::SharedMemoryHandle memory_handle(
    200       base::FileDescriptor(static_cast<int>(os_buffer.value), false), size,
    201       guid);
    202 #endif
    203 
    204   base::SharedMemory memory(memory_handle, false);
    205   memory.Map(message.size());
    206   ASSERT_TRUE(memory.memory());
    207 
    208   EXPECT_TRUE(std::equal(message.begin(), message.end(),
    209                          static_cast<const char*>(memory.memory())));
    210 
    211   // Verify that the received buffer's internal GUID was preserved in transit.
    212   EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE));
    213   std::vector<uint8_t> guid_bytes;
    214   EXPECT_EQ(MOJO_RESULT_OK,
    215             ReadMessageRaw(MessagePipeHandle(h), &guid_bytes, nullptr,
    216                            MOJO_READ_MESSAGE_FLAG_NONE));
    217   EXPECT_EQ(sizeof(MojoSharedBufferGuid), guid_bytes.size());
    218   auto* expected_guid =
    219       reinterpret_cast<MojoSharedBufferGuid*>(guid_bytes.data());
    220   EXPECT_EQ(expected_guid->high, mojo_guid.high);
    221   EXPECT_EQ(expected_guid->low, mojo_guid.low);
    222 }
    223 
    224 TEST_F(PlatformWrapperTest, InvalidHandle) {
    225   // Wrap an invalid platform handle and expect to unwrap the same.
    226 
    227   MojoHandle wrapped_handle;
    228   MojoPlatformHandle invalid_handle;
    229   invalid_handle.struct_size = sizeof(MojoPlatformHandle);
    230   invalid_handle.type = MOJO_PLATFORM_HANDLE_TYPE_INVALID;
    231   EXPECT_EQ(MOJO_RESULT_OK,
    232             MojoWrapPlatformHandle(&invalid_handle, nullptr, &wrapped_handle));
    233   EXPECT_EQ(MOJO_RESULT_OK,
    234             MojoUnwrapPlatformHandle(wrapped_handle, nullptr, &invalid_handle));
    235   EXPECT_EQ(MOJO_PLATFORM_HANDLE_TYPE_INVALID, invalid_handle.type);
    236 }
    237 
    238 TEST_F(PlatformWrapperTest, InvalidArgument) {
    239   // Try to wrap an invalid MojoPlatformHandle struct and expect an error.
    240   MojoHandle wrapped_handle;
    241   MojoPlatformHandle platform_handle;
    242   platform_handle.struct_size = 0;
    243   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
    244             MojoWrapPlatformHandle(&platform_handle, nullptr, &wrapped_handle));
    245 }
    246 
    247 }  // namespace
    248 }  // namespace core
    249 }  // namespace mojo
    250