Add most of base/ build/ buildtools/ testing/ third_party/googletest/

Enough to make ./tools/gn/bootstrap/bootstrap.py work on Linux.

Change-Id: I94de95f1ce87dd3672d1a99c62254edee8be45bd
Reviewed-on: https://gn-review.googlesource.com/1100
Reviewed-by: Petr Hosek <phosek@google.com>
Commit-Queue: Scott Graham <scottmg@chromium.org>
diff --git a/base/posix/eintr_wrapper.h b/base/posix/eintr_wrapper.h
new file mode 100644
index 0000000..c0ffced
--- /dev/null
+++ b/base/posix/eintr_wrapper.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2012 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.
+
+// This provides a wrapper around system calls which may be interrupted by a
+// signal and return EINTR. See man 7 signal.
+// To prevent long-lasting loops (which would likely be a bug, such as a signal
+// that should be masked) to go unnoticed, there is a limit after which the
+// caller will nonetheless see an EINTR in Debug builds.
+//
+// On Windows and Fuchsia, this wrapper macro does nothing because there are no
+// signals.
+//
+// Don't wrap close calls in HANDLE_EINTR. Use IGNORE_EINTR if the return
+// value of close is significant. See http://crbug.com/269623.
+
+#ifndef BASE_POSIX_EINTR_WRAPPER_H_
+#define BASE_POSIX_EINTR_WRAPPER_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_POSIX) && !defined(OS_FUCHSIA)
+
+#include <errno.h>
+
+#if defined(NDEBUG)
+
+#define HANDLE_EINTR(x) ({ \
+  decltype(x) eintr_wrapper_result; \
+  do { \
+    eintr_wrapper_result = (x); \
+  } while (eintr_wrapper_result == -1 && errno == EINTR); \
+  eintr_wrapper_result; \
+})
+
+#else
+
+#define HANDLE_EINTR(x) ({ \
+  int eintr_wrapper_counter = 0; \
+  decltype(x) eintr_wrapper_result; \
+  do { \
+    eintr_wrapper_result = (x); \
+  } while (eintr_wrapper_result == -1 && errno == EINTR && \
+           eintr_wrapper_counter++ < 100); \
+  eintr_wrapper_result; \
+})
+
+#endif  // NDEBUG
+
+#define IGNORE_EINTR(x) ({ \
+  decltype(x) eintr_wrapper_result; \
+  do { \
+    eintr_wrapper_result = (x); \
+    if (eintr_wrapper_result == -1 && errno == EINTR) { \
+      eintr_wrapper_result = 0; \
+    } \
+  } while (0); \
+  eintr_wrapper_result; \
+})
+
+#else  // !OS_POSIX || OS_FUCHSIA
+
+#define HANDLE_EINTR(x) (x)
+#define IGNORE_EINTR(x) (x)
+
+#endif  // !OS_POSIX || OS_FUCHSIA
+
+#endif  // BASE_POSIX_EINTR_WRAPPER_H_
diff --git a/base/posix/file_descriptor_shuffle.cc b/base/posix/file_descriptor_shuffle.cc
new file mode 100644
index 0000000..d2fd39a
--- /dev/null
+++ b/base/posix/file_descriptor_shuffle.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2011 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 "base/posix/file_descriptor_shuffle.h"
+
+#include <unistd.h>
+#include <stddef.h>
+#include <ostream>
+
+#include "base/posix/eintr_wrapper.h"
+#include "base/logging.h"
+
+namespace base {
+
+bool PerformInjectiveMultimapDestructive(
+    InjectiveMultimap* m, InjectionDelegate* delegate) {
+  static const size_t kMaxExtraFDs = 16;
+  int extra_fds[kMaxExtraFDs];
+  unsigned next_extra_fd = 0;
+
+  // DANGER: this function must not allocate or lock.
+  // Cannot use STL iterators here, since debug iterators use locks.
+
+  for (size_t i_index = 0; i_index < m->size(); ++i_index) {
+    InjectiveMultimap::value_type* i = &(*m)[i_index];
+    int temp_fd = -1;
+
+    // We DCHECK the injectiveness of the mapping.
+    for (size_t j_index = i_index + 1; j_index < m->size(); ++j_index) {
+      InjectiveMultimap::value_type* j = &(*m)[j_index];
+      DCHECK(i->dest != j->dest) << "Both fd " << i->source
+          << " and " << j->source << " map to " << i->dest;
+    }
+
+    const bool is_identity = i->source == i->dest;
+
+    for (size_t j_index = i_index + 1; j_index < m->size(); ++j_index) {
+      InjectiveMultimap::value_type* j = &(*m)[j_index];
+      if (!is_identity && i->dest == j->source) {
+        if (temp_fd == -1) {
+          if (!delegate->Duplicate(&temp_fd, i->dest))
+            return false;
+          if (next_extra_fd < kMaxExtraFDs) {
+            extra_fds[next_extra_fd++] = temp_fd;
+          } else {
+            RAW_LOG(ERROR, "PerformInjectiveMultimapDestructive overflowed "
+                           "extra_fds. Leaking file descriptors!");
+          }
+        }
+
+        j->source = temp_fd;
+        j->close = false;
+      }
+
+      if (i->close && i->source == j->dest)
+        i->close = false;
+
+      if (i->close && i->source == j->source) {
+        i->close = false;
+        j->close = true;
+      }
+    }
+
+    if (!is_identity) {
+      if (!delegate->Move(i->source, i->dest))
+        return false;
+    }
+
+    if (!is_identity && i->close)
+      delegate->Close(i->source);
+  }
+
+  for (unsigned i = 0; i < next_extra_fd; i++)
+    delegate->Close(extra_fds[i]);
+
+  return true;
+}
+
+bool PerformInjectiveMultimap(const InjectiveMultimap& m_in,
+                              InjectionDelegate* delegate) {
+  InjectiveMultimap m(m_in);
+  return PerformInjectiveMultimapDestructive(&m, delegate);
+}
+
+bool FileDescriptorTableInjection::Duplicate(int* result, int fd) {
+  *result = HANDLE_EINTR(dup(fd));
+  return *result >= 0;
+}
+
+bool FileDescriptorTableInjection::Move(int src, int dest) {
+  return HANDLE_EINTR(dup2(src, dest)) != -1;
+}
+
+void FileDescriptorTableInjection::Close(int fd) {
+  int ret = IGNORE_EINTR(close(fd));
+  DPCHECK(ret == 0);
+}
+
+}  // namespace base
diff --git a/base/posix/file_descriptor_shuffle.h b/base/posix/file_descriptor_shuffle.h
new file mode 100644
index 0000000..2afdc28
--- /dev/null
+++ b/base/posix/file_descriptor_shuffle.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2011 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.
+
+#ifndef BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_
+#define BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_
+
+// This code exists to shuffle file descriptors, which is commonly needed when
+// forking subprocesses. The naive approach (just call dup2 to set up the
+// desired descriptors) is very simple, but wrong: it won't handle edge cases
+// (like mapping 0 -> 1, 1 -> 0) correctly.
+//
+// In order to unittest this code, it's broken into the abstract action (an
+// injective multimap) and the concrete code for dealing with file descriptors.
+// Users should use the code like this:
+//   base::InjectiveMultimap file_descriptor_map;
+//   file_descriptor_map.push_back(base::InjectionArc(devnull, 0, true));
+//   file_descriptor_map.push_back(base::InjectionArc(devnull, 2, true));
+//   file_descriptor_map.push_back(base::InjectionArc(pipe[1], 1, true));
+//   base::ShuffleFileDescriptors(file_descriptor_map);
+//
+// and trust the the Right Thing will get done.
+
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+
+// A Delegate which performs the actions required to perform an injective
+// multimapping in place.
+class InjectionDelegate {
+ public:
+  // Duplicate |fd|, an element of the domain, and write a fresh element of the
+  // domain into |result|. Returns true iff successful.
+  virtual bool Duplicate(int* result, int fd) = 0;
+  // Destructively move |src| to |dest|, overwriting |dest|. Returns true iff
+  // successful.
+  virtual bool Move(int src, int dest) = 0;
+  // Delete an element of the domain.
+  virtual void Close(int fd) = 0;
+
+ protected:
+  virtual ~InjectionDelegate() = default;
+};
+
+// An implementation of the InjectionDelegate interface using the file
+// descriptor table of the current process as the domain.
+class BASE_EXPORT FileDescriptorTableInjection : public InjectionDelegate {
+  bool Duplicate(int* result, int fd) override;
+  bool Move(int src, int dest) override;
+  void Close(int fd) override;
+};
+
+// A single arc of the directed graph which describes an injective multimapping.
+struct InjectionArc {
+  InjectionArc(int in_source, int in_dest, bool in_close)
+      : source(in_source),
+        dest(in_dest),
+        close(in_close) {
+  }
+
+  int source;
+  int dest;
+  bool close;  // if true, delete the source element after performing the
+               // mapping.
+};
+
+typedef std::vector<InjectionArc> InjectiveMultimap;
+
+BASE_EXPORT bool PerformInjectiveMultimap(const InjectiveMultimap& map,
+                                          InjectionDelegate* delegate);
+
+BASE_EXPORT bool PerformInjectiveMultimapDestructive(
+    InjectiveMultimap* map,
+    InjectionDelegate* delegate);
+
+// This function will not call malloc but will mutate |map|
+static inline bool ShuffleFileDescriptors(InjectiveMultimap* map) {
+  FileDescriptorTableInjection delegate;
+  return PerformInjectiveMultimapDestructive(map, &delegate);
+}
+
+}  // namespace base
+
+#endif  // BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_
diff --git a/base/posix/file_descriptor_shuffle_unittest.cc b/base/posix/file_descriptor_shuffle_unittest.cc
new file mode 100644
index 0000000..3dfbf7e
--- /dev/null
+++ b/base/posix/file_descriptor_shuffle_unittest.cc
@@ -0,0 +1,281 @@
+// Copyright (c) 2012 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 "base/posix/file_descriptor_shuffle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// 'Duplicated' file descriptors start at this number
+const int kDuplicateBase = 1000;
+
+}  // namespace
+
+namespace base {
+
+struct Action {
+  enum Type {
+    CLOSE,
+    MOVE,
+    DUPLICATE,
+  };
+
+  Action(Type in_type, int in_fd1, int in_fd2 = -1)
+      : type(in_type),
+        fd1(in_fd1),
+        fd2(in_fd2) {
+  }
+
+  bool operator==(const Action& other) const {
+    return other.type == type &&
+           other.fd1 == fd1 &&
+           other.fd2 == fd2;
+  }
+
+  Type type;
+  int fd1;
+  int fd2;
+};
+
+class InjectionTracer : public InjectionDelegate {
+ public:
+  InjectionTracer()
+      : next_duplicate_(kDuplicateBase) {
+  }
+
+  bool Duplicate(int* result, int fd) override {
+    *result = next_duplicate_++;
+    actions_.push_back(Action(Action::DUPLICATE, *result, fd));
+    return true;
+  }
+
+  bool Move(int src, int dest) override {
+    actions_.push_back(Action(Action::MOVE, src, dest));
+    return true;
+  }
+
+  void Close(int fd) override { actions_.push_back(Action(Action::CLOSE, fd)); }
+
+  const std::vector<Action>& actions() const { return actions_; }
+
+ private:
+  int next_duplicate_;
+  std::vector<Action> actions_;
+};
+
+TEST(FileDescriptorShuffleTest, Empty) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  EXPECT_EQ(0u, tracer.actions().size());
+}
+
+TEST(FileDescriptorShuffleTest, Noop) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 0, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  EXPECT_EQ(0u, tracer.actions().size());
+}
+
+TEST(FileDescriptorShuffleTest, NoopAndClose) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 0, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  EXPECT_EQ(0u, tracer.actions().size());
+}
+
+TEST(FileDescriptorShuffleTest, Simple1) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(1u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+}
+
+TEST(FileDescriptorShuffleTest, Simple2) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, false));
+  map.push_back(InjectionArc(2, 3, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(2u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 2, 3));
+}
+
+TEST(FileDescriptorShuffleTest, Simple3) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(2u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::CLOSE, 0));
+}
+
+TEST(FileDescriptorShuffleTest, Simple4) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(10, 0, true));
+  map.push_back(InjectionArc(1, 1, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(2u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 10, 0));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::CLOSE, 10));
+}
+
+TEST(FileDescriptorShuffleTest, Cycle) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, false));
+  map.push_back(InjectionArc(1, 0, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(4u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] ==
+              Action(Action::DUPLICATE, kDuplicateBase, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
+  EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
+}
+
+TEST(FileDescriptorShuffleTest, CycleAndClose1) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, true));
+  map.push_back(InjectionArc(1, 0, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(4u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] ==
+              Action(Action::DUPLICATE, kDuplicateBase, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
+  EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
+}
+
+TEST(FileDescriptorShuffleTest, CycleAndClose2) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, false));
+  map.push_back(InjectionArc(1, 0, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(4u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] ==
+              Action(Action::DUPLICATE, kDuplicateBase, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
+  EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
+}
+
+TEST(FileDescriptorShuffleTest, CycleAndClose3) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, true));
+  map.push_back(InjectionArc(1, 0, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(4u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] ==
+              Action(Action::DUPLICATE, kDuplicateBase, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
+  EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
+}
+
+TEST(FileDescriptorShuffleTest, Fanout) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, false));
+  map.push_back(InjectionArc(0, 2, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(2u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
+}
+
+TEST(FileDescriptorShuffleTest, FanoutAndClose1) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, true));
+  map.push_back(InjectionArc(0, 2, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(3u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
+}
+
+TEST(FileDescriptorShuffleTest, FanoutAndClose2) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, false));
+  map.push_back(InjectionArc(0, 2, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(3u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
+}
+
+TEST(FileDescriptorShuffleTest, FanoutAndClose3) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, true));
+  map.push_back(InjectionArc(0, 2, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(3u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
+}
+
+class FailingDelegate : public InjectionDelegate {
+ public:
+  bool Duplicate(int* result, int fd) override { return false; }
+
+  bool Move(int src, int dest) override { return false; }
+
+  void Close(int fd) override {}
+};
+
+TEST(FileDescriptorShuffleTest, EmptyWithFailure) {
+  InjectiveMultimap map;
+  FailingDelegate failing;
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &failing));
+}
+
+TEST(FileDescriptorShuffleTest, NoopWithFailure) {
+  InjectiveMultimap map;
+  FailingDelegate failing;
+  map.push_back(InjectionArc(0, 0, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &failing));
+}
+
+TEST(FileDescriptorShuffleTest, Simple1WithFailure) {
+  InjectiveMultimap map;
+  FailingDelegate failing;
+  map.push_back(InjectionArc(0, 1, false));
+
+  EXPECT_FALSE(PerformInjectiveMultimap(map, &failing));
+}
+
+}  // namespace base
diff --git a/base/posix/global_descriptors.cc b/base/posix/global_descriptors.cc
new file mode 100644
index 0000000..738d14e
--- /dev/null
+++ b/base/posix/global_descriptors.cc
@@ -0,0 +1,101 @@
+// Copyright (c) 2012 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 "base/posix/global_descriptors.h"
+
+#include <vector>
+#include <utility>
+
+#include "base/logging.h"
+
+namespace base {
+
+GlobalDescriptors::Descriptor::Descriptor(Key key, int fd)
+    : key(key), fd(fd), region(base::MemoryMappedFile::Region::kWholeFile) {
+}
+
+GlobalDescriptors::Descriptor::Descriptor(Key key,
+                                          int fd,
+                                          base::MemoryMappedFile::Region region)
+    : key(key), fd(fd), region(region) {
+}
+
+// static
+GlobalDescriptors* GlobalDescriptors::GetInstance() {
+  typedef Singleton<base::GlobalDescriptors,
+                    LeakySingletonTraits<base::GlobalDescriptors> >
+      GlobalDescriptorsSingleton;
+  return GlobalDescriptorsSingleton::get();
+}
+
+int GlobalDescriptors::Get(Key key) const {
+  const int ret = MaybeGet(key);
+
+  if (ret == -1)
+    DLOG(DCHECK) << "Unknown global descriptor: " << key;
+  return ret;
+}
+
+int GlobalDescriptors::MaybeGet(Key key) const {
+  for (Mapping::const_iterator
+       i = descriptors_.begin(); i != descriptors_.end(); ++i) {
+    if (i->key == key)
+      return i->fd;
+  }
+
+  return -1;
+}
+
+base::ScopedFD GlobalDescriptors::TakeFD(
+    Key key,
+    base::MemoryMappedFile::Region* region) {
+  base::ScopedFD fd;
+  for (Mapping::iterator i = descriptors_.begin(); i != descriptors_.end();
+       ++i) {
+    if (i->key == key) {
+      *region = i->region;
+      fd.reset(i->fd);
+      descriptors_.erase(i);
+      break;
+    }
+  }
+  return fd;
+}
+
+void GlobalDescriptors::Set(Key key, int fd) {
+  Set(key, fd, base::MemoryMappedFile::Region::kWholeFile);
+}
+
+void GlobalDescriptors::Set(Key key,
+                            int fd,
+                            base::MemoryMappedFile::Region region) {
+  for (auto& i : descriptors_) {
+    if (i.key == key) {
+      i.fd = fd;
+      i.region = region;
+      return;
+    }
+  }
+
+  descriptors_.push_back(Descriptor(key, fd, region));
+}
+
+base::MemoryMappedFile::Region GlobalDescriptors::GetRegion(Key key) const {
+  for (const auto& i : descriptors_) {
+    if (i.key == key)
+      return i.region;
+  }
+  DLOG(DCHECK) << "Unknown global descriptor: " << key;
+  return base::MemoryMappedFile::Region::kWholeFile;
+}
+
+void GlobalDescriptors::Reset(const Mapping& mapping) {
+  descriptors_ = mapping;
+}
+
+GlobalDescriptors::GlobalDescriptors() = default;
+
+GlobalDescriptors::~GlobalDescriptors() = default;
+
+}  // namespace base
diff --git a/base/posix/global_descriptors.h b/base/posix/global_descriptors.h
new file mode 100644
index 0000000..9d68761
--- /dev/null
+++ b/base/posix/global_descriptors.h
@@ -0,0 +1,98 @@
+// Copyright (c) 2012 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.
+
+#ifndef BASE_POSIX_GLOBAL_DESCRIPTORS_H_
+#define BASE_POSIX_GLOBAL_DESCRIPTORS_H_
+
+#include "build/build_config.h"
+
+#include <vector>
+#include <utility>
+
+#include <stdint.h>
+
+#include "base/files/memory_mapped_file.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/singleton.h"
+
+namespace base {
+
+// It's common practice to install file descriptors into well known slot
+// numbers before execing a child; stdin, stdout and stderr are ubiqutous
+// examples.
+//
+// However, when using a zygote model, this becomes troublesome. Since the
+// descriptors which need to be in these slots generally aren't known, any code
+// could open a resource and take one of the reserved descriptors. Simply
+// overwriting the slot isn't a viable solution.
+//
+// We could try to fill the reserved slots as soon as possible, but this is a
+// fragile solution since global constructors etc are able to open files.
+//
+// Instead, we retreat from the idea of installing descriptors in specific
+// slots and add a layer of indirection in the form of this singleton object.
+// It maps from an abstract key to a descriptor. If independent modules each
+// need to define keys, then values should be chosen randomly so as not to
+// collide.
+//
+// Note that this class is deprecated and passing file descriptor should ideally
+// be done through the command line and using FileDescriptorStore.
+// See https://crbugs.com/detail?id=692619
+class BASE_EXPORT GlobalDescriptors {
+ public:
+  typedef uint32_t Key;
+  struct Descriptor {
+    Descriptor(Key key, int fd);
+    Descriptor(Key key, int fd, base::MemoryMappedFile::Region region);
+
+    // Globally unique key.
+    Key key;
+    // Actual FD.
+    int fd;
+    // Optional region, defaults to kWholeFile.
+    base::MemoryMappedFile::Region region;
+  };
+  typedef std::vector<Descriptor> Mapping;
+
+  // Often we want a canonical descriptor for a given Key. In this case, we add
+  // the following constant to the key value:
+  static const int kBaseDescriptor = 3;  // 0, 1, 2 are already taken.
+
+  // Return the singleton instance of GlobalDescriptors.
+  static GlobalDescriptors* GetInstance();
+
+  // Get a descriptor given a key. It is a fatal error if the key is not known.
+  int Get(Key key) const;
+
+  // Get a descriptor given a key. Returns -1 on error.
+  int MaybeGet(Key key) const;
+
+  // Returns a descriptor given a key and removes it from this class mappings.
+  // Also populates |region|.
+  // It is a fatal error if the key is not known.
+  base::ScopedFD TakeFD(Key key, base::MemoryMappedFile::Region* region);
+
+  // Get a region given a key. It is a fatal error if the key is not known.
+  base::MemoryMappedFile::Region GetRegion(Key key) const;
+
+  // Set the descriptor for the given |key|. This sets the region associated
+  // with |key| to kWholeFile.
+  void Set(Key key, int fd);
+
+  // Set the descriptor and |region| for the given |key|.
+  void Set(Key key, int fd, base::MemoryMappedFile::Region region);
+
+  void Reset(const Mapping& mapping);
+
+ private:
+  friend struct DefaultSingletonTraits<GlobalDescriptors>;
+  GlobalDescriptors();
+  ~GlobalDescriptors();
+
+  Mapping descriptors_;
+};
+
+}  // namespace base
+
+#endif  // BASE_POSIX_GLOBAL_DESCRIPTORS_H_
diff --git a/base/posix/safe_strerror.cc b/base/posix/safe_strerror.cc
new file mode 100644
index 0000000..aef5742
--- /dev/null
+++ b/base/posix/safe_strerror.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2006-2009 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.
+
+#if defined(__ANDROID__)
+// Post-L versions of bionic define the GNU-specific strerror_r if _GNU_SOURCE
+// is defined, but the symbol is renamed to __gnu_strerror_r which only exists
+// on those later versions. To preserve ABI compatibility with older versions,
+// undefine _GNU_SOURCE and use the POSIX version.
+#undef _GNU_SOURCE
+#endif
+
+#include "base/posix/safe_strerror.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "build/build_config.h"
+
+namespace base {
+
+#if defined(__GLIBC__) || defined(OS_NACL)
+#define USE_HISTORICAL_STRERRO_R 1
+#else
+#define USE_HISTORICAL_STRERRO_R 0
+#endif
+
+#if USE_HISTORICAL_STRERRO_R && defined(__GNUC__)
+// GCC will complain about the unused second wrap function unless we tell it
+// that we meant for them to be potentially unused, which is exactly what this
+// attribute is for.
+#define POSSIBLY_UNUSED __attribute__((unused))
+#else
+#define POSSIBLY_UNUSED
+#endif
+
+#if USE_HISTORICAL_STRERRO_R
+// glibc has two strerror_r functions: a historical GNU-specific one that
+// returns type char *, and a POSIX.1-2001 compliant one available since 2.3.4
+// that returns int. This wraps the GNU-specific one.
+static void POSSIBLY_UNUSED wrap_posix_strerror_r(
+    char *(*strerror_r_ptr)(int, char *, size_t),
+    int err,
+    char *buf,
+    size_t len) {
+  // GNU version.
+  char *rc = (*strerror_r_ptr)(err, buf, len);
+  if (rc != buf) {
+    // glibc did not use buf and returned a static string instead. Copy it
+    // into buf.
+    buf[0] = '\0';
+    strncat(buf, rc, len - 1);
+  }
+  // The GNU version never fails. Unknown errors get an "unknown error" message.
+  // The result is always null terminated.
+}
+#endif  // USE_HISTORICAL_STRERRO_R
+
+// Wrapper for strerror_r functions that implement the POSIX interface. POSIX
+// does not define the behaviour for some of the edge cases, so we wrap it to
+// guarantee that they are handled. This is compiled on all POSIX platforms, but
+// it will only be used on Linux if the POSIX strerror_r implementation is
+// being used (see below).
+static void POSSIBLY_UNUSED wrap_posix_strerror_r(
+    int (*strerror_r_ptr)(int, char *, size_t),
+    int err,
+    char *buf,
+    size_t len) {
+  int old_errno = errno;
+  // Have to cast since otherwise we get an error if this is the GNU version
+  // (but in such a scenario this function is never called). Sadly we can't use
+  // C++-style casts because the appropriate one is reinterpret_cast but it's
+  // considered illegal to reinterpret_cast a type to itself, so we get an
+  // error in the opposite case.
+  int result = (*strerror_r_ptr)(err, buf, len);
+  if (result == 0) {
+    // POSIX is vague about whether the string will be terminated, although
+    // it indirectly implies that typically ERANGE will be returned, instead
+    // of truncating the string. We play it safe by always terminating the
+    // string explicitly.
+    buf[len - 1] = '\0';
+  } else {
+    // Error. POSIX is vague about whether the return value is itself a system
+    // error code or something else. On Linux currently it is -1 and errno is
+    // set. On BSD-derived systems it is a system error and errno is unchanged.
+    // We try and detect which case it is so as to put as much useful info as
+    // we can into our message.
+    int strerror_error;  // The error encountered in strerror
+    int new_errno = errno;
+    if (new_errno != old_errno) {
+      // errno was changed, so probably the return value is just -1 or something
+      // else that doesn't provide any info, and errno is the error.
+      strerror_error = new_errno;
+    } else {
+      // Either the error from strerror_r was the same as the previous value, or
+      // errno wasn't used. Assume the latter.
+      strerror_error = result;
+    }
+    // snprintf truncates and always null-terminates.
+    snprintf(buf,
+             len,
+             "Error %d while retrieving error %d",
+             strerror_error,
+             err);
+  }
+  errno = old_errno;
+}
+
+void safe_strerror_r(int err, char *buf, size_t len) {
+  if (buf == nullptr || len <= 0) {
+    return;
+  }
+  // If using glibc (i.e., Linux), the compiler will automatically select the
+  // appropriate overloaded function based on the function type of strerror_r.
+  // The other one will be elided from the translation unit since both are
+  // static.
+  wrap_posix_strerror_r(&strerror_r, err, buf, len);
+}
+
+std::string safe_strerror(int err) {
+  const int buffer_size = 256;
+  char buf[buffer_size];
+  safe_strerror_r(err, buf, sizeof(buf));
+  return std::string(buf);
+}
+
+}  // namespace base
diff --git a/base/posix/safe_strerror.h b/base/posix/safe_strerror.h
new file mode 100644
index 0000000..2945312
--- /dev/null
+++ b/base/posix/safe_strerror.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 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.
+
+#ifndef BASE_POSIX_SAFE_STRERROR_H_
+#define BASE_POSIX_SAFE_STRERROR_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+
+// BEFORE using anything from this file, first look at PLOG and friends in
+// logging.h and use them instead if applicable.
+//
+// This file declares safe, portable alternatives to the POSIX strerror()
+// function. strerror() is inherently unsafe in multi-threaded apps and should
+// never be used. Doing so can cause crashes. Additionally, the thread-safe
+// alternative strerror_r varies in semantics across platforms. Use these
+// functions instead.
+
+// Thread-safe strerror function with dependable semantics that never fails.
+// It will write the string form of error "err" to buffer buf of length len.
+// If there is an error calling the OS's strerror_r() function then a message to
+// that effect will be printed into buf, truncating if necessary. The final
+// result is always null-terminated. The value of errno is never changed.
+//
+// Use this instead of strerror_r().
+BASE_EXPORT void safe_strerror_r(int err, char *buf, size_t len);
+
+// Calls safe_strerror_r with a buffer of suitable size and returns the result
+// in a C++ string.
+//
+// Use this instead of strerror(). Note though that safe_strerror_r will be
+// more robust in the case of heap corruption errors, since it doesn't need to
+// allocate a string.
+BASE_EXPORT std::string safe_strerror(int err);
+
+}  // namespace base
+
+#endif  // BASE_POSIX_SAFE_STRERROR_H_
diff --git a/base/posix/unix_domain_socket.cc b/base/posix/unix_domain_socket.cc
new file mode 100644
index 0000000..7c087a5
--- /dev/null
+++ b/base/posix/unix_domain_socket.cc
@@ -0,0 +1,288 @@
+// Copyright (c) 2011 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 "base/posix/unix_domain_socket.h"
+
+#include <errno.h>
+#include <sys/socket.h>
+#if !defined(OS_NACL_NONSFI)
+#include <sys/un.h>
+#endif
+#include <unistd.h>
+
+#include <vector>
+
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/pickle.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/stl_util.h"
+#include "build/build_config.h"
+
+#if !defined(OS_NACL_NONSFI)
+#include <sys/uio.h>
+#endif
+
+namespace base {
+
+const size_t UnixDomainSocket::kMaxFileDescriptors = 16;
+
+#if !defined(OS_NACL_NONSFI)
+bool CreateSocketPair(ScopedFD* one, ScopedFD* two) {
+  int raw_socks[2];
+#if defined(OS_MACOSX)
+  // macOS does not support SEQPACKET.
+  const int flags = SOCK_STREAM;
+#else
+  const int flags = SOCK_SEQPACKET;
+#endif
+  if (socketpair(AF_UNIX, flags, 0, raw_socks) == -1)
+    return false;
+#if defined(OS_MACOSX)
+  // On macOS, preventing SIGPIPE is done with socket option.
+  const int no_sigpipe = 1;
+  if (setsockopt(raw_socks[0], SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe,
+                 sizeof(no_sigpipe)) != 0)
+    return false;
+  if (setsockopt(raw_socks[1], SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe,
+                 sizeof(no_sigpipe)) != 0)
+    return false;
+#endif
+  one->reset(raw_socks[0]);
+  two->reset(raw_socks[1]);
+  return true;
+}
+
+// static
+bool UnixDomainSocket::EnableReceiveProcessId(int fd) {
+#if !defined(OS_MACOSX)
+  const int enable = 1;
+  return setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable)) == 0;
+#else
+  // SO_PASSCRED is not supported on macOS.
+  return true;
+#endif  // OS_MACOSX
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+// static
+bool UnixDomainSocket::SendMsg(int fd,
+                               const void* buf,
+                               size_t length,
+                               const std::vector<int>& fds) {
+  struct msghdr msg = {};
+  struct iovec iov = {const_cast<void*>(buf), length};
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+
+  char* control_buffer = nullptr;
+  if (fds.size()) {
+    const unsigned control_len = CMSG_SPACE(sizeof(int) * fds.size());
+    control_buffer = new char[control_len];
+
+    struct cmsghdr* cmsg;
+    msg.msg_control = control_buffer;
+    msg.msg_controllen = control_len;
+    cmsg = CMSG_FIRSTHDR(&msg);
+    cmsg->cmsg_level = SOL_SOCKET;
+    cmsg->cmsg_type = SCM_RIGHTS;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fds.size());
+    memcpy(CMSG_DATA(cmsg), &fds[0], sizeof(int) * fds.size());
+    msg.msg_controllen = cmsg->cmsg_len;
+  }
+
+// Avoid a SIGPIPE if the other end breaks the connection.
+// Due to a bug in the Linux kernel (net/unix/af_unix.c) MSG_NOSIGNAL isn't
+// regarded for SOCK_SEQPACKET in the AF_UNIX domain, but it is mandated by
+// POSIX. On Mac MSG_NOSIGNAL is not supported, so we need to ensure that
+// SO_NOSIGPIPE is set during socket creation.
+#if defined(OS_MACOSX)
+  const int flags = 0;
+  int no_sigpipe = 0;
+  socklen_t no_sigpipe_len = sizeof(no_sigpipe);
+  DPCHECK(getsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe,
+                     &no_sigpipe_len) == 0)
+      << "Failed ot get socket option.";
+  DCHECK(no_sigpipe) << "SO_NOSIGPIPE not set on the socket.";
+#else
+  const int flags = MSG_NOSIGNAL;
+#endif  // OS_MACOSX
+  const ssize_t r = HANDLE_EINTR(sendmsg(fd, &msg, flags));
+  const bool ret = static_cast<ssize_t>(length) == r;
+  delete[] control_buffer;
+  return ret;
+}
+
+// static
+ssize_t UnixDomainSocket::RecvMsg(int fd,
+                                  void* buf,
+                                  size_t length,
+                                  std::vector<ScopedFD>* fds) {
+  return UnixDomainSocket::RecvMsgWithPid(fd, buf, length, fds, nullptr);
+}
+
+// static
+ssize_t UnixDomainSocket::RecvMsgWithPid(int fd,
+                                         void* buf,
+                                         size_t length,
+                                         std::vector<ScopedFD>* fds,
+                                         ProcessId* pid) {
+  return UnixDomainSocket::RecvMsgWithFlags(fd, buf, length, 0, fds, pid);
+}
+
+// static
+ssize_t UnixDomainSocket::RecvMsgWithFlags(int fd,
+                                           void* buf,
+                                           size_t length,
+                                           int flags,
+                                           std::vector<ScopedFD>* fds,
+                                           ProcessId* out_pid) {
+  fds->clear();
+
+  struct msghdr msg = {};
+  struct iovec iov = {buf, length};
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+
+  const size_t kControlBufferSize =
+      CMSG_SPACE(sizeof(int) * kMaxFileDescriptors)
+#if !defined(OS_NACL_NONSFI) && !defined(OS_MACOSX)
+      // The PNaCl toolchain for Non-SFI binary build and macOS do not support
+      // ucred. macOS supports xucred, but this structure is insufficient.
+      + CMSG_SPACE(sizeof(struct ucred))
+#endif  // OS_NACL_NONSFI or OS_MACOSX
+      ;
+  char control_buffer[kControlBufferSize];
+  msg.msg_control = control_buffer;
+  msg.msg_controllen = sizeof(control_buffer);
+
+  const ssize_t r = HANDLE_EINTR(recvmsg(fd, &msg, flags));
+  if (r == -1)
+    return -1;
+
+  int* wire_fds = nullptr;
+  unsigned wire_fds_len = 0;
+  ProcessId pid = -1;
+
+  if (msg.msg_controllen > 0) {
+    struct cmsghdr* cmsg;
+    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+      const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
+      if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+        DCHECK_EQ(payload_len % sizeof(int), 0u);
+        DCHECK_EQ(wire_fds, static_cast<void*>(nullptr));
+        wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
+        wire_fds_len = payload_len / sizeof(int);
+      }
+#if !defined(OS_NACL_NONSFI) && !defined(OS_MACOSX)
+      // The PNaCl toolchain for Non-SFI binary build and macOS do not support
+      // SCM_CREDENTIALS.
+      if (cmsg->cmsg_level == SOL_SOCKET &&
+          cmsg->cmsg_type == SCM_CREDENTIALS) {
+        DCHECK_EQ(payload_len, sizeof(struct ucred));
+        DCHECK_EQ(pid, -1);
+        pid = reinterpret_cast<struct ucred*>(CMSG_DATA(cmsg))->pid;
+      }
+#endif  // !defined(OS_NACL_NONSFI) && !defined(OS_MACOSX)
+    }
+  }
+
+  if (msg.msg_flags & MSG_TRUNC || msg.msg_flags & MSG_CTRUNC) {
+    if (msg.msg_flags & MSG_CTRUNC) {
+      // Extraordinary case, not caller fixable. Log something.
+      LOG(ERROR) << "recvmsg returned MSG_CTRUNC flag, buffer len is "
+                 << msg.msg_controllen;
+    }
+    for (unsigned i = 0; i < wire_fds_len; ++i)
+      close(wire_fds[i]);
+    errno = EMSGSIZE;
+    return -1;
+  }
+
+  if (wire_fds) {
+    for (unsigned i = 0; i < wire_fds_len; ++i)
+      fds->push_back(ScopedFD(wire_fds[i]));  // TODO(mdempsky): emplace_back
+  }
+
+  if (out_pid) {
+#if defined(OS_MACOSX)
+    socklen_t pid_size = sizeof(pid);
+    if (getsockopt(fd, SOL_LOCAL, LOCAL_PEERPID, &pid, &pid_size) != 0)
+      pid = -1;
+#else
+    // |pid| will legitimately be -1 if we read EOF, so only DCHECK if we
+    // actually received a message.  Unfortunately, Linux allows sending zero
+    // length messages, which are indistinguishable from EOF, so this check
+    // has false negatives.
+    if (r > 0 || msg.msg_controllen > 0)
+      DCHECK_GE(pid, 0);
+#endif
+
+    *out_pid = pid;
+  }
+
+  return r;
+}
+
+#if !defined(OS_NACL_NONSFI)
+// static
+ssize_t UnixDomainSocket::SendRecvMsg(int fd,
+                                      uint8_t* reply,
+                                      unsigned max_reply_len,
+                                      int* result_fd,
+                                      const Pickle& request) {
+  return UnixDomainSocket::SendRecvMsgWithFlags(fd, reply, max_reply_len,
+                                                0, /* recvmsg_flags */
+                                                result_fd, request);
+}
+
+// static
+ssize_t UnixDomainSocket::SendRecvMsgWithFlags(int fd,
+                                               uint8_t* reply,
+                                               unsigned max_reply_len,
+                                               int recvmsg_flags,
+                                               int* result_fd,
+                                               const Pickle& request) {
+  // This socketpair is only used for the IPC and is cleaned up before
+  // returning.
+  ScopedFD recv_sock, send_sock;
+  if (!CreateSocketPair(&recv_sock, &send_sock))
+    return -1;
+
+  {
+    std::vector<int> send_fds;
+    send_fds.push_back(send_sock.get());
+    if (!SendMsg(fd, request.data(), request.size(), send_fds))
+      return -1;
+  }
+
+  // Close the sending end of the socket right away so that if our peer closes
+  // it before sending a response (e.g., from exiting), RecvMsgWithFlags() will
+  // return EOF instead of hanging.
+  send_sock.reset();
+
+  std::vector<ScopedFD> recv_fds;
+  // When porting to OSX keep in mind it doesn't support MSG_NOSIGNAL, so the
+  // sender might get a SIGPIPE.
+  const ssize_t reply_len = RecvMsgWithFlags(
+      recv_sock.get(), reply, max_reply_len, recvmsg_flags, &recv_fds, nullptr);
+  recv_sock.reset();
+  if (reply_len == -1)
+    return -1;
+
+  // If we received more file descriptors than caller expected, then we treat
+  // that as an error.
+  if (recv_fds.size() > (result_fd != nullptr ? 1 : 0)) {
+    NOTREACHED();
+    return -1;
+  }
+
+  if (result_fd)
+    *result_fd = recv_fds.empty() ? -1 : recv_fds[0].release();
+
+  return reply_len;
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+}  // namespace base
diff --git a/base/posix/unix_domain_socket.h b/base/posix/unix_domain_socket.h
new file mode 100644
index 0000000..5c74f07
--- /dev/null
+++ b/base/posix/unix_domain_socket.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2011 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.
+
+#ifndef BASE_POSIX_UNIX_DOMAIN_SOCKET_H_
+#define BASE_POSIX_UNIX_DOMAIN_SOCKET_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/files/scoped_file.h"
+#include "base/process/process_handle.h"
+#include "build/build_config.h"
+
+namespace base {
+
+class Pickle;
+
+#if !defined(OS_NACL_NONSFI)
+// Creates a connected pair of UNIX-domain SOCK_SEQPACKET sockets, and passes
+// ownership of the newly allocated file descriptors to |one| and |two|.
+// Returns true on success.
+bool BASE_EXPORT CreateSocketPair(ScopedFD* one, ScopedFD* two);
+#endif
+
+class BASE_EXPORT UnixDomainSocket {
+ public:
+  // Maximum number of file descriptors that can be read by RecvMsg().
+  static const size_t kMaxFileDescriptors;
+
+#if !defined(OS_NACL_NONSFI)
+  // Use to enable receiving process IDs in RecvMsgWithPid.  Should be called on
+  // the receiving socket (i.e., the socket passed to RecvMsgWithPid). Returns
+  // true if successful.
+  static bool EnableReceiveProcessId(int fd);
+#endif  // !defined(OS_NACL_NONSFI)
+
+  // Use sendmsg to write the given msg and include a vector of file
+  // descriptors. Returns true if successful.
+  static bool SendMsg(int fd,
+                      const void* msg,
+                      size_t length,
+                      const std::vector<int>& fds);
+
+  // Use recvmsg to read a message and an array of file descriptors. Returns
+  // -1 on failure. Note: will read, at most, |kMaxFileDescriptors| descriptors.
+  static ssize_t RecvMsg(int fd,
+                         void* msg,
+                         size_t length,
+                         std::vector<ScopedFD>* fds);
+
+  // Same as RecvMsg above, but also returns the sender's process ID (as seen
+  // from the caller's namespace).  However, before using this function to
+  // receive process IDs, EnableReceiveProcessId() should be called on the
+  // receiving socket.
+  static ssize_t RecvMsgWithPid(int fd,
+                                void* msg,
+                                size_t length,
+                                std::vector<ScopedFD>* fds,
+                                ProcessId* pid);
+
+#if !defined(OS_NACL_NONSFI)
+  // Perform a sendmsg/recvmsg pair.
+  //   1. This process creates a UNIX SEQPACKET socketpair. Using
+  //      connection-oriented sockets (SEQPACKET or STREAM) is critical here,
+  //      because if one of the ends closes the other one must be notified.
+  //   2. This process writes a request to |fd| with an SCM_RIGHTS control
+  //      message containing on end of the fresh socket pair.
+  //   3. This process blocks reading from the other end of the fresh
+  //      socketpair.
+  //   4. The target process receives the request, processes it and writes the
+  //      reply to the end of the socketpair contained in the request.
+  //   5. This process wakes up and continues.
+  //
+  //   fd: descriptor to send the request on
+  //   reply: buffer for the reply
+  //   reply_len: size of |reply|
+  //   result_fd: (may be NULL) the file descriptor returned in the reply
+  //              (if any)
+  //   request: the bytes to send in the request
+  static ssize_t SendRecvMsg(int fd,
+                             uint8_t* reply,
+                             unsigned reply_len,
+                             int* result_fd,
+                             const Pickle& request);
+
+  // Similar to SendRecvMsg(), but |recvmsg_flags| allows to control the flags
+  // of the recvmsg(2) call.
+  static ssize_t SendRecvMsgWithFlags(int fd,
+                                      uint8_t* reply,
+                                      unsigned reply_len,
+                                      int recvmsg_flags,
+                                      int* result_fd,
+                                      const Pickle& request);
+#endif  // !defined(OS_NACL_NONSFI)
+ private:
+  // Similar to RecvMsg, but allows to specify |flags| for recvmsg(2).
+  static ssize_t RecvMsgWithFlags(int fd,
+                                  void* msg,
+                                  size_t length,
+                                  int flags,
+                                  std::vector<ScopedFD>* fds,
+                                  ProcessId* pid);
+};
+
+}  // namespace base
+
+#endif  // BASE_POSIX_UNIX_DOMAIN_SOCKET_H_
diff --git a/base/posix/unix_domain_socket_unittest.cc b/base/posix/unix_domain_socket_unittest.cc
new file mode 100644
index 0000000..453064f
--- /dev/null
+++ b/base/posix/unix_domain_socket_unittest.cc
@@ -0,0 +1,183 @@
+// Copyright (c) 2013 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 "build/build_config.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/location.h"
+#include "base/pickle.h"
+#include "base/posix/unix_domain_socket.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// Callers should use ASSERT_NO_FATAL_FAILURE with this function, to
+// ensure that execution is aborted if the function has assertion failure.
+void CreateSocketPair(int fds[2]) {
+#if defined(OS_MACOSX)
+  // Mac OS does not support SOCK_SEQPACKET.
+  int flags = SOCK_STREAM;
+#else
+  int flags = SOCK_SEQPACKET;
+#endif
+  ASSERT_EQ(0, socketpair(AF_UNIX, flags, 0, fds));
+#if defined(OS_MACOSX)
+  // On OSX an attempt to read or write to a closed socket may generate a
+  // SIGPIPE rather than returning -1, corrected with SO_NOSIGPIPE option.
+  int nosigpipe = 1;
+  ASSERT_EQ(0, setsockopt(fds[0], SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe,
+                          sizeof(nosigpipe)));
+  ASSERT_EQ(0, setsockopt(fds[1], SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe,
+                          sizeof(nosigpipe)));
+#endif
+}
+
+TEST(UnixDomainSocketTest, SendRecvMsgAbortOnReplyFDClose) {
+  Thread message_thread("UnixDomainSocketTest");
+  ASSERT_TRUE(message_thread.Start());
+  int fds[2];
+  ASSERT_NO_FATAL_FAILURE(CreateSocketPair(fds));
+  ScopedFD scoped_fd0(fds[0]);
+  ScopedFD scoped_fd1(fds[1]);
+
+  // Have the thread send a synchronous message via the socket.
+  Pickle request;
+  message_thread.task_runner()->PostTask(
+      FROM_HERE, BindOnce(IgnoreResult(&UnixDomainSocket::SendRecvMsg), fds[1],
+                          nullptr, 0U, nullptr, request));
+
+  // Receive the message.
+  std::vector<ScopedFD> message_fds;
+  uint8_t buffer[16];
+  ASSERT_EQ(
+      static_cast<int>(request.size()),
+      UnixDomainSocket::RecvMsg(fds[0], buffer, sizeof(buffer), &message_fds));
+  ASSERT_EQ(1U, message_fds.size());
+
+  // Close the reply FD.
+  message_fds.clear();
+
+  // Check that the thread didn't get blocked.
+  WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC,
+                      WaitableEvent::InitialState::NOT_SIGNALED);
+  message_thread.task_runner()->PostTask(
+      FROM_HERE, BindOnce(&WaitableEvent::Signal, Unretained(&event)));
+  ASSERT_TRUE(event.TimedWait(TimeDelta::FromMilliseconds(5000)));
+}
+
+TEST(UnixDomainSocketTest, SendRecvMsgAvoidsSIGPIPE) {
+  // Make sure SIGPIPE isn't being ignored.
+  struct sigaction act = {}, oldact;
+  act.sa_handler = SIG_DFL;
+  ASSERT_EQ(0, sigaction(SIGPIPE, &act, &oldact));
+  int fds[2];
+  ASSERT_NO_FATAL_FAILURE(CreateSocketPair(fds));
+  ScopedFD scoped_fd1(fds[1]);
+  ASSERT_EQ(0, IGNORE_EINTR(close(fds[0])));
+
+  // Have the thread send a synchronous message via the socket. Unless the
+  // message is sent with MSG_NOSIGNAL, this shall result in SIGPIPE.
+  Pickle request;
+  ASSERT_EQ(
+      -1, UnixDomainSocket::SendRecvMsg(fds[1], nullptr, 0U, nullptr, request));
+  ASSERT_EQ(EPIPE, errno);
+  // Restore the SIGPIPE handler.
+  ASSERT_EQ(0, sigaction(SIGPIPE, &oldact, nullptr));
+}
+
+// Simple sanity check within a single process that receiving PIDs works.
+TEST(UnixDomainSocketTest, RecvPid) {
+  int fds[2];
+  ASSERT_NO_FATAL_FAILURE(CreateSocketPair(fds));
+  ScopedFD recv_sock(fds[0]);
+  ScopedFD send_sock(fds[1]);
+
+  ASSERT_TRUE(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
+
+  static const char kHello[] = "hello";
+  ASSERT_TRUE(UnixDomainSocket::SendMsg(send_sock.get(), kHello, sizeof(kHello),
+                                        std::vector<int>()));
+
+  // Extra receiving buffer space to make sure we really received only
+  // sizeof(kHello) bytes and it wasn't just truncated to fit the buffer.
+  char buf[sizeof(kHello) + 1];
+  ProcessId sender_pid;
+  std::vector<ScopedFD> fd_vec;
+  const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
+      recv_sock.get(), buf, sizeof(buf), &fd_vec, &sender_pid);
+  ASSERT_EQ(sizeof(kHello), static_cast<size_t>(nread));
+  ASSERT_EQ(0, memcmp(buf, kHello, sizeof(kHello)));
+  ASSERT_EQ(0U, fd_vec.size());
+
+  ASSERT_EQ(getpid(), sender_pid);
+}
+
+// Same as above, but send the max number of file descriptors too.
+TEST(UnixDomainSocketTest, RecvPidWithMaxDescriptors) {
+  int fds[2];
+  ASSERT_NO_FATAL_FAILURE(CreateSocketPair(fds));
+  ScopedFD recv_sock(fds[0]);
+  ScopedFD send_sock(fds[1]);
+
+  ASSERT_TRUE(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
+
+  static const char kHello[] = "hello";
+  std::vector<int> send_fds(UnixDomainSocket::kMaxFileDescriptors,
+                            send_sock.get());
+  ASSERT_TRUE(UnixDomainSocket::SendMsg(send_sock.get(), kHello, sizeof(kHello),
+                                        send_fds));
+
+  // Extra receiving buffer space to make sure we really received only
+  // sizeof(kHello) bytes and it wasn't just truncated to fit the buffer.
+  char buf[sizeof(kHello) + 1];
+  ProcessId sender_pid;
+  std::vector<ScopedFD> recv_fds;
+  const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
+      recv_sock.get(), buf, sizeof(buf), &recv_fds, &sender_pid);
+  ASSERT_EQ(sizeof(kHello), static_cast<size_t>(nread));
+  ASSERT_EQ(0, memcmp(buf, kHello, sizeof(kHello)));
+  ASSERT_EQ(UnixDomainSocket::kMaxFileDescriptors, recv_fds.size());
+
+  ASSERT_EQ(getpid(), sender_pid);
+}
+
+// Check that RecvMsgWithPid doesn't DCHECK fail when reading EOF from a
+// disconnected socket.
+TEST(UnixDomianSocketTest, RecvPidDisconnectedSocket) {
+  int fds[2];
+  ASSERT_NO_FATAL_FAILURE(CreateSocketPair(fds));
+  ScopedFD recv_sock(fds[0]);
+  ScopedFD send_sock(fds[1]);
+
+  ASSERT_TRUE(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
+
+  send_sock.reset();
+
+  char ch;
+  ProcessId sender_pid;
+  std::vector<ScopedFD> recv_fds;
+  const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
+      recv_sock.get(), &ch, sizeof(ch), &recv_fds, &sender_pid);
+  ASSERT_EQ(0, nread);
+  ASSERT_EQ(-1, sender_pid);
+  ASSERT_EQ(0U, recv_fds.size());
+}
+
+}  // namespace
+
+}  // namespace base