platform_wrapper_unittest.cc 10 KB

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