ppapi: Add SHARED_MEMORY_REGION type to SerializedHandle

This CL adds a new SHARED_MEMORY_REGION type to the SerializedHandle. This new
type is backed up by the base::subtle::PlatformSharedMemoryRegion class that
provides a new recommended API for the shared memory in Chrome.
Eventually, all uses of the SHARED_MEMORY type should be converted to the
SHARED_MEMORY_REGION.

Bug: 845985
Change-Id: Icfb4605dadb6f111efe953d8b940cc879fa40763
Reviewed-on: https://chromium-review.googlesource.com/1076334
Reviewed-by: Ken Rockot <[email protected]>
Reviewed-by: Bill Budge <[email protected]>
Reviewed-by: Daniel Cheng <[email protected]>
Reviewed-by: Derek Schuff <[email protected]>
Commit-Queue: Alexandr Ilin <[email protected]>
Cr-Commit-Position: refs/heads/master@{#563500}
diff --git a/components/nacl/loader/nacl_ipc_adapter.cc b/components/nacl/loader/nacl_ipc_adapter.cc
index 4727192..4c884f9 100644
--- a/components/nacl/loader/nacl_ipc_adapter.cc
+++ b/components/nacl/loader/nacl_ipc_adapter.cc
@@ -254,6 +254,25 @@
 #endif
 }
 
+std::unique_ptr<NaClDescWrapper> MakeShmRegionNaClDesc(
+    base::subtle::PlatformSharedMemoryRegion region) {
+  // Writable regions are not supported in NaCl.
+  DCHECK_NE(region.GetMode(),
+            base::subtle::PlatformSharedMemoryRegion::Mode::kWritable);
+  size_t size = region.GetSize();
+  base::subtle::PlatformSharedMemoryRegion::ScopedPlatformHandle handle =
+      region.PassPlatformHandle();
+  return std::make_unique<NaClDescWrapper>(
+#if defined(OS_MACOSX)
+      NaClDescImcShmMachMake(handle.release(),
+#elif defined(OS_WIN)
+      NaClDescImcShmMake(handle.Take(),
+#else
+      NaClDescImcShmMake(handle.fd.release(),
+#endif
+                             size));
+}
+
 }  // namespace
 
 class NaClIPCAdapter::RewrittenMessage {
@@ -556,24 +575,26 @@
 
     // Now add any descriptors we found to rewritten_msg. |handles| is usually
     // empty, unless we read a message containing a FD or handle.
-    for (Handles::const_iterator iter = handles.begin();
-         iter != handles.end();
-         ++iter) {
+    for (ppapi::proxy::SerializedHandle& handle : handles) {
       std::unique_ptr<NaClDescWrapper> nacl_desc;
-      switch (iter->type()) {
+      switch (handle.type()) {
         case ppapi::proxy::SerializedHandle::SHARED_MEMORY: {
-          nacl_desc =
-              MakeShmNaClDesc(iter->shmem(), static_cast<size_t>(iter->size()));
+          nacl_desc = MakeShmNaClDesc(handle.shmem(),
+                                      static_cast<size_t>(handle.size()));
+          break;
+        }
+        case ppapi::proxy::SerializedHandle::SHARED_MEMORY_REGION: {
+          nacl_desc = MakeShmRegionNaClDesc(handle.TakeSharedMemoryRegion());
           break;
         }
         case ppapi::proxy::SerializedHandle::SOCKET: {
           nacl_desc.reset(new NaClDescWrapper(NaClDescSyncSocketMake(
 #if defined(OS_WIN)
-              iter->descriptor().GetHandle()
+              handle.descriptor().GetHandle()
 #else
-              iter->descriptor().fd
+              handle.descriptor().fd
 #endif
-              )));
+                  )));
           break;
         }
         case ppapi::proxy::SerializedHandle::FILE: {
@@ -581,15 +602,14 @@
           // required, wrap it in a NaClDescQuota.
           NaClDesc* desc = NaClDescIoMakeFromHandle(
 #if defined(OS_WIN)
-              iter->descriptor().GetHandle(),
+              handle.descriptor().GetHandle(),
 #else
-              iter->descriptor().fd,
+              handle.descriptor().fd,
 #endif
-              TranslatePepperFileReadWriteOpenFlags(iter->open_flags()));
-          if (desc && iter->file_io()) {
+              TranslatePepperFileReadWriteOpenFlags(handle.open_flags()));
+          if (desc && handle.file_io()) {
             desc = MakeNaClDescQuota(
-                locked_data_.nacl_msg_scanner_.GetFile(iter->file_io()),
-                desc);
+                locked_data_.nacl_msg_scanner_.GetFile(handle.file_io()), desc);
           }
           if (desc)
             nacl_desc.reset(new NaClDescWrapper(desc));
diff --git a/ipc/ipc_message_utils.cc b/ipc/ipc_message_utils.cc
index 5618b5c..208080d 100644
--- a/ipc/ipc_message_utils.cc
+++ b/ipc/ipc_message_utils.cc
@@ -876,6 +876,8 @@
 void ParamTraits<base::subtle::PlatformSharedMemoryRegion>::Write(
     base::Pickle* m,
     const param_type& p) {
+  // This serialization must be kept in sync with
+  // nacl_message_scanner.cc::WriteHandle().
   const bool valid = p.IsValid();
   WriteParam(m, valid);
 
@@ -1259,8 +1261,6 @@
                                                 const param_type& p) {
   DCHECK(!p.is_empty());
 
-  // This serialization must be kept in sync with
-  // nacl_message_scanner.cc:WriteHandle().
   ParamTraits<uint64_t>::Write(m, p.GetHighForSerialization());
   ParamTraits<uint64_t>::Write(m, p.GetLowForSerialization());
 }
diff --git a/ppapi/proxy/nacl_message_scanner.cc b/ppapi/proxy/nacl_message_scanner.cc
index b6f04d6..4fae6974 100644
--- a/ppapi/proxy/nacl_message_scanner.cc
+++ b/ppapi/proxy/nacl_message_scanner.cc
@@ -62,17 +62,32 @@
   if (handle.type() == SerializedHandle::SHARED_MEMORY) {
     // Now write the handle itself in POSIX style.
     // This serialization must be kept in sync with
-    // ParamTraits<SharedMemoryHandle>::Write and
-    // ParamTraits<UnguessableToken>::Write.
+    // ParamTraits<SharedMemoryHandle>::Write.
     if (handle.shmem().IsValid()) {
       msg->WriteBool(true);  // valid == true
       msg->WriteInt(handle_index);
-      msg->WriteUInt64(handle.shmem().GetGUID().GetHighForSerialization());
-      msg->WriteUInt64(handle.shmem().GetGUID().GetLowForSerialization());
+      IPC::WriteParam(msg, handle.shmem().GetGUID());
       msg->WriteUInt64(handle.shmem().GetSize());
     } else {
       msg->WriteBool(false);  // valid == false
     }
+  } else if (handle.type() == SerializedHandle::SHARED_MEMORY_REGION) {
+    // Write the region in POSIX style.
+    // This serialization must be kept in sync with
+    // ParamTraits<PlatformSharedMemoryRegion>::Write.
+    const auto& region = handle.shmem_region();
+    if (region.IsValid()) {
+      IPC::WriteParam(msg, true);  // valid == true
+      IPC::WriteParam(msg, region.GetMode());
+      IPC::WriteParam(msg, static_cast<uint64_t>(region.GetSize()));
+      IPC::WriteParam(msg, region.GetGUID());
+      // Writable regions are not supported, so write only one handle index.
+      DCHECK_NE(region.GetMode(),
+                base::subtle::PlatformSharedMemoryRegion::Mode::kWritable);
+      IPC::WriteParam(msg, handle_index);
+    } else {
+      msg->WriteBool(false);  // valid == false
+    }
   } else if (handle.type() != SerializedHandle::INVALID) {
     // Now write the handle itself in POSIX style.
     // This serialization must be kept in sync with
diff --git a/ppapi/proxy/ppapi_param_traits.cc b/ppapi/proxy/ppapi_param_traits.cc
index 822c61f..b663e82 100644
--- a/ppapi/proxy/ppapi_param_traits.cc
+++ b/ppapi/proxy/ppapi_param_traits.cc
@@ -238,6 +238,9 @@
     case ppapi::proxy::SerializedHandle::SHARED_MEMORY:
       WriteParam(m, p.shmem());
       break;
+    case ppapi::proxy::SerializedHandle::SHARED_MEMORY_REGION:
+      WriteParam(m, const_cast<param_type&>(p).TakeSharedMemoryRegion());
+      break;
     case ppapi::proxy::SerializedHandle::SOCKET:
     case ppapi::proxy::SerializedHandle::FILE:
       WriteParam(m, p.descriptor());
@@ -259,33 +262,37 @@
   switch (header.type) {
     case ppapi::proxy::SerializedHandle::SHARED_MEMORY: {
       base::SharedMemoryHandle handle;
-      if (ReadParam(m, iter, &handle)) {
-        r->set_shmem(handle, header.size);
-        return true;
-      }
+      if (!ReadParam(m, iter, &handle))
+        return false;
+      r->set_shmem(handle, header.size);
+      break;
+    }
+    case ppapi::proxy::SerializedHandle::SHARED_MEMORY_REGION: {
+      base::subtle::PlatformSharedMemoryRegion region;
+      if (!ReadParam(m, iter, &region))
+        return false;
+      r->set_shmem_region(std::move(region));
       break;
     }
     case ppapi::proxy::SerializedHandle::SOCKET: {
       IPC::PlatformFileForTransit socket;
-      if (ReadParam(m, iter, &socket)) {
-        r->set_socket(socket);
-        return true;
-      }
+      if (!ReadParam(m, iter, &socket))
+        return false;
+      r->set_socket(socket);
       break;
     }
     case ppapi::proxy::SerializedHandle::FILE: {
       IPC::PlatformFileForTransit desc;
-      if (ReadParam(m, iter, &desc)) {
-        r->set_file_handle(desc, header.open_flags, header.file_io);
-        return true;
-      }
+      if (!ReadParam(m, iter, &desc))
+        return false;
+      r->set_file_handle(desc, header.open_flags, header.file_io);
       break;
     }
     case ppapi::proxy::SerializedHandle::INVALID:
-      return true;
-    // No default so the compiler will warn us if a new type is added.
+      break;
+      // No default so the compiler will warn us if a new type is added.
   }
-  return false;
+  return true;
 }
 
 // static
diff --git a/ppapi/proxy/serialized_handle.cc b/ppapi/proxy/serialized_handle.cc
index 13811b5..92f945d 100644
--- a/ppapi/proxy/serialized_handle.cc
+++ b/ppapi/proxy/serialized_handle.cc
@@ -29,6 +29,7 @@
     : type_(other.type_),
       shm_handle_(other.shm_handle_),
       size_(other.size_),
+      shm_region_(std::move(other.shm_region_)),
       descriptor_(other.descriptor_),
       open_flags_(other.open_flags_),
       file_io_(other.file_io_) {
@@ -40,6 +41,7 @@
   type_ = other.type_;
   shm_handle_ = other.shm_handle_;
   size_ = other.size_;
+  shm_region_ = std::move(other.shm_region_);
   descriptor_ = other.descriptor_;
   open_flags_ = other.open_flags_;
   file_io_ = other.file_io_;
@@ -65,6 +67,19 @@
       file_io_(0) {}
 
 SerializedHandle::SerializedHandle(
+    base::subtle::PlatformSharedMemoryRegion region)
+    : type_(SHARED_MEMORY_REGION),
+      size_(0),
+      shm_region_(std::move(region)),
+      descriptor_(IPC::InvalidPlatformFileForTransit()),
+      open_flags_(0),
+      file_io_(0) {
+  // Writable regions are not supported.
+  DCHECK_NE(shm_region_.GetMode(),
+            base::subtle::PlatformSharedMemoryRegion::Mode::kWritable);
+}
+
+SerializedHandle::SerializedHandle(
     Type type,
     const IPC::PlatformFileForTransit& socket_descriptor)
     : type_(type),
@@ -78,6 +93,8 @@
   switch (type_) {
     case SHARED_MEMORY:
       return base::SharedMemory::IsHandleValid(shm_handle_);
+    case SHARED_MEMORY_REGION:
+      return shm_region_.IsValid();
     case SOCKET:
     case FILE:
       return !(IPC::InvalidPlatformFileForTransit() == descriptor_);
@@ -97,6 +114,9 @@
       case SHARED_MEMORY:
         base::SharedMemory::CloseHandle(shm_handle_);
         break;
+      case SHARED_MEMORY_REGION:
+        shm_region_ = base::subtle::PlatformSharedMemoryRegion();
+        break;
       case SOCKET:
       case FILE:
         base::File file_closer = IPC::PlatformFileForTransitToFile(descriptor_);
@@ -144,6 +164,7 @@
       valid_type = true;
       break;
     }
+    case SHARED_MEMORY_REGION:
     case SOCKET:
     case INVALID:
       valid_type = true;
diff --git a/ppapi/proxy/serialized_handle.h b/ppapi/proxy/serialized_handle.h
index cc1c6b4..c82008a3 100644
--- a/ppapi/proxy/serialized_handle.h
+++ b/ppapi/proxy/serialized_handle.h
@@ -12,6 +12,7 @@
 
 #include "base/atomicops.h"
 #include "base/logging.h"
+#include "base/memory/platform_shared_memory_region.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/shared_memory.h"
 #include "build/build_config.h"
@@ -32,7 +33,9 @@
 // NaClIPCAdapter for use in NaCl.
 class PPAPI_PROXY_EXPORT SerializedHandle {
  public:
-  enum Type { INVALID, SHARED_MEMORY, SOCKET, FILE };
+  // TODO(https://crbug.com/845985): Remove SHARED_MEMORY type after all clients
+  // will be converted to the SHARED_MEMORY_REGION.
+  enum Type { INVALID, SHARED_MEMORY, SHARED_MEMORY_REGION, SOCKET, FILE };
   // Header contains the fields that we send in IPC messages, apart from the
   // actual handle. See comments on the SerializedHandle fields below.
   struct Header {
@@ -62,12 +65,16 @@
   // Create a shared memory handle.
   SerializedHandle(const base::SharedMemoryHandle& handle, uint32_t size);
 
+  // Create a shared memory region handle.
+  explicit SerializedHandle(base::subtle::PlatformSharedMemoryRegion region);
+
   // Create a socket or file handle.
   SerializedHandle(const Type type,
                    const IPC::PlatformFileForTransit& descriptor);
 
   Type type() const { return type_; }
   bool is_shmem() const { return type_ == SHARED_MEMORY; }
+  bool is_shmem_region() const { return type_ == SHARED_MEMORY_REGION; }
   bool is_socket() const { return type_ == SOCKET; }
   bool is_file() const { return type_ == FILE; }
   const base::SharedMemoryHandle& shmem() const {
@@ -78,6 +85,14 @@
     DCHECK(is_shmem());
     return size_;
   }
+  const base::subtle::PlatformSharedMemoryRegion& shmem_region() const {
+    DCHECK(is_shmem_region());
+    return shm_region_;
+  }
+  base::subtle::PlatformSharedMemoryRegion TakeSharedMemoryRegion() {
+    DCHECK(is_shmem_region());
+    return std::move(shm_region_);
+  }
   const IPC::PlatformFileForTransit& descriptor() const {
     DCHECK(is_socket() || is_file());
     return descriptor_;
@@ -92,11 +107,24 @@
     size_ = size;
 
     descriptor_ = IPC::InvalidPlatformFileForTransit();
+    shm_region_ = base::subtle::PlatformSharedMemoryRegion();
+  }
+  void set_shmem_region(base::subtle::PlatformSharedMemoryRegion region) {
+    type_ = SHARED_MEMORY_REGION;
+    shm_region_ = std::move(region);
+    // Writable regions are not supported.
+    DCHECK_NE(shm_region_.GetMode(),
+              base::subtle::PlatformSharedMemoryRegion::Mode::kWritable);
+
+    descriptor_ = IPC::InvalidPlatformFileForTransit();
+    shm_handle_ = base::SharedMemoryHandle();
+    size_ = 0;
   }
   void set_socket(const IPC::PlatformFileForTransit& socket) {
     type_ = SOCKET;
     descriptor_ = socket;
 
+    shm_region_ = base::subtle::PlatformSharedMemoryRegion();
     shm_handle_ = base::SharedMemoryHandle();
     size_ = 0;
   }
@@ -106,6 +134,7 @@
     type_ = FILE;
 
     descriptor_ = descriptor;
+    shm_region_ = base::subtle::PlatformSharedMemoryRegion();
     shm_handle_ = base::SharedMemoryHandle();
     size_ = 0;
     open_flags_ = open_flags;
@@ -115,6 +144,7 @@
     type_ = INVALID;
 
     shm_handle_ = base::SharedMemoryHandle();
+    shm_region_ = base::subtle::PlatformSharedMemoryRegion();
     size_ = 0;
     descriptor_ = IPC::InvalidPlatformFileForTransit();
   }
@@ -152,6 +182,9 @@
   base::SharedMemoryHandle shm_handle_;
   uint32_t size_;
 
+  // This is valid if type == SHARED_MEMORY_REGION.
+  base::subtle::PlatformSharedMemoryRegion shm_region_;
+
   // This is valid if type == SOCKET || type == FILE.
   IPC::PlatformFileForTransit descriptor_;