Construct ProcessMemoryLinux using PtraceConnection

Update ProcessMemoryLinux to be constructed from PtraceConnection
instead of being Initialize()d with a pid_t.

This allows consolidating PtraceClient's BrokeredMemory with
ProcessMemoryLinux and providing the PtraceConnection as a alternative
to the memory file (previously only done for brokered connections).

Change-Id: Id81e51d1eec25b63994c21ab3eaa62bb3ae84caf
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3072402
Reviewed-by: Mark Mentovai <mark@chromium.org>
Commit-Queue: Joshua Peraza <jperaza@chromium.org>
GitOrigin-RevId: 78bcb55e1c7baa5badbd7ff7685ab63da17aab6a
diff --git a/snapshot/crashpad_types/crashpad_info_reader_test.cc b/snapshot/crashpad_types/crashpad_info_reader_test.cc
index ebc6a4d..556ead1 100644
--- a/snapshot/crashpad_types/crashpad_info_reader_test.cc
+++ b/snapshot/crashpad_types/crashpad_info_reader_test.cc
@@ -30,6 +30,10 @@
 #include "util/misc/from_pointer_cast.h"
 #include "util/process/process_memory_native.h"
 
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#include "test/linux/fake_ptrace_connection.h"
+#endif
+
 namespace crashpad {
 namespace test {
 namespace {
@@ -102,8 +106,14 @@
                         VMAddress extra_memory_address,
                         VMAddress simple_annotations_address,
                         VMAddress annotations_list_address) {
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+  FakePtraceConnection connection;
+  ASSERT_TRUE(connection.Initialize(process));
+  ProcessMemoryLinux memory(&connection);
+#else
   ProcessMemoryNative memory;
   ASSERT_TRUE(memory.Initialize(process));
+#endif
 
   ProcessMemoryRange range;
   ASSERT_TRUE(range.Initialize(&memory, is_64_bit));
diff --git a/snapshot/crashpad_types/image_annotation_reader_test.cc b/snapshot/crashpad_types/image_annotation_reader_test.cc
index 72a637b..9d9970e 100644
--- a/snapshot/crashpad_types/image_annotation_reader_test.cc
+++ b/snapshot/crashpad_types/image_annotation_reader_test.cc
@@ -32,6 +32,10 @@
 #include "util/misc/from_pointer_cast.h"
 #include "util/process/process_memory_native.h"
 
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#include "test/linux/fake_ptrace_connection.h"
+#endif
+
 namespace crashpad {
 namespace test {
 namespace {
@@ -90,8 +94,14 @@
                        bool is_64_bit,
                        VMAddress simple_map_address,
                        VMAddress annotation_list_address) {
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+  FakePtraceConnection connection;
+  ASSERT_TRUE(connection.Initialize(process));
+  ProcessMemoryLinux memory(&connection);
+#else
   ProcessMemoryNative memory;
   ASSERT_TRUE(memory.Initialize(process));
+#endif
 
   ProcessMemoryRange range;
   ASSERT_TRUE(range.Initialize(&memory, is_64_bit));
diff --git a/snapshot/elf/elf_image_reader_test.cc b/snapshot/elf/elf_image_reader_test.cc
index 63da92a..2ea55ad 100644
--- a/snapshot/elf/elf_image_reader_test.cc
+++ b/snapshot/elf/elf_image_reader_test.cc
@@ -127,21 +127,22 @@
   constexpr bool am_64_bit = false;
 #endif  // ARCH_CPU_64_BITS
 
-  ProcessMemoryNative memory;
-  ASSERT_TRUE(memory.Initialize(process));
-  ProcessMemoryRange range;
-  ASSERT_TRUE(range.Initialize(&memory, am_64_bit));
-
   VMAddress elf_address;
 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
   FakePtraceConnection connection;
   ASSERT_TRUE(connection.Initialize(process));
+  ProcessMemoryLinux memory(&connection);
   LocateExecutable(&connection, &memory, &elf_address);
 #elif defined(OS_FUCHSIA)
+  ProcessMemoryFuchsia memory;
+  ASSERT_TRUE(memory.Initialize(process));
   LocateExecutable(process, &memory, &elf_address);
 #endif
   ASSERT_NO_FATAL_FAILURE();
 
+  ProcessMemoryRange range;
+  ASSERT_TRUE(range.Initialize(&memory, am_64_bit));
+
   ElfImageReader reader;
   ASSERT_TRUE(reader.Initialize(range, elf_address));
 
@@ -191,8 +192,15 @@
   constexpr bool am_64_bit = false;
 #endif  // ARCH_CPU_64_BITS
 
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+  FakePtraceConnection connection;
+  ASSERT_TRUE(connection.Initialize(process));
+  ProcessMemoryLinux memory(&connection);
+#else
   ProcessMemoryNative memory;
   ASSERT_TRUE(memory.Initialize(process));
+#endif
+
   ProcessMemoryRange range;
   ASSERT_TRUE(range.Initialize(&memory, am_64_bit));
 
diff --git a/snapshot/linux/debug_rendezvous_test.cc b/snapshot/linux/debug_rendezvous_test.cc
index d32bd19..41956aa 100644
--- a/snapshot/linux/debug_rendezvous_test.cc
+++ b/snapshot/linux/debug_rendezvous_test.cc
@@ -83,8 +83,7 @@
   ASSERT_EQ(exe_mappings->Count(), 1u);
   LinuxVMAddress elf_address = exe_mappings->Next()->range.Base();
 
-  ProcessMemoryLinux memory;
-  ASSERT_TRUE(memory.Initialize(connection->GetProcessID()));
+  ProcessMemoryLinux memory(connection);
   ProcessMemoryRange range;
   ASSERT_TRUE(range.Initialize(&memory, connection->Is64Bit()));
 
diff --git a/snapshot/sanitized/sanitization_information_test.cc b/snapshot/sanitized/sanitization_information_test.cc
index f386442..425ec75 100644
--- a/snapshot/sanitized/sanitization_information_test.cc
+++ b/snapshot/sanitized/sanitization_information_test.cc
@@ -20,6 +20,10 @@
 #include "util/misc/from_pointer_cast.h"
 #include "util/process/process_memory_linux.h"
 
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#include "test/linux/fake_ptrace_connection.h"
+#endif
+
 namespace crashpad {
 namespace test {
 namespace {
@@ -27,11 +31,12 @@
 class AllowedAnnotationsTest : public testing::Test {
  public:
   void SetUp() override {
-    ASSERT_TRUE(memory_.Initialize(getpid()));
+    ASSERT_TRUE(connection_.Initialize(getpid()));
+
 #if defined(ARCH_CPU_64_BITS)
-    ASSERT_TRUE(range_.Initialize(&memory_, true));
+    ASSERT_TRUE(range_.Initialize(connection_.Memory(), true));
 #else
-    ASSERT_TRUE(range_.Initialize(&memory_, false));
+    ASSERT_TRUE(range_.Initialize(connection_.Memory(), false));
 #endif
   }
 
@@ -41,7 +46,7 @@
         range_, FromPointerCast<VMAddress>(address), &allowed_annotations_);
   }
 
-  ProcessMemoryLinux memory_;
+  FakePtraceConnection connection_;
   ProcessMemoryRange range_;
   std::vector<std::string> allowed_annotations_;
 };
diff --git a/test/linux/fake_ptrace_connection.cc b/test/linux/fake_ptrace_connection.cc
index d556045..774a340 100644
--- a/test/linux/fake_ptrace_connection.cc
+++ b/test/linux/fake_ptrace_connection.cc
@@ -83,12 +83,7 @@
 ProcessMemory* FakePtraceConnection::Memory() {
   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
   if (!memory_) {
-    auto mem = std::make_unique<ProcessMemoryLinux>();
-    if (mem->Initialize(pid_)) {
-      memory_ = std::move(mem);
-    } else {
-      ADD_FAILURE();
-    }
+    memory_ = std::make_unique<ProcessMemoryLinux>(this);
   }
   return memory_.get();
 }
@@ -99,5 +94,12 @@
   return false;
 }
 
+ssize_t FakePtraceConnection::ReadUpTo(VMAddress address,
+                                       size_t size,
+                                       void* buffer) {
+  NOTREACHED();
+  return false;
+}
+
 }  // namespace test
 }  // namespace crashpad
diff --git a/test/linux/fake_ptrace_connection.h b/test/linux/fake_ptrace_connection.h
index 01a6f92..79cdbd9 100644
--- a/test/linux/fake_ptrace_connection.h
+++ b/test/linux/fake_ptrace_connection.h
@@ -65,6 +65,9 @@
   //! \todo Not yet implemented.
   bool Threads(std::vector<pid_t>* threads) override;
 
+  //! \\todo Not yet implemented.
+  ssize_t ReadUpTo(VMAddress address, size_t size, void* buffer) override;
+
  private:
   std::set<pid_t> attachments_;
   std::unique_ptr<ProcessMemoryLinux> memory_;
diff --git a/util/linux/auxiliary_vector_test.cc b/util/linux/auxiliary_vector_test.cc
index 00af5ab..2f6c942 100644
--- a/util/linux/auxiliary_vector_test.cc
+++ b/util/linux/auxiliary_vector_test.cc
@@ -95,8 +95,7 @@
   ASSERT_TRUE(aux.GetValue(AT_EGID, &egid));
   EXPECT_EQ(egid, getegid());
 
-  ProcessMemoryLinux memory;
-  ASSERT_TRUE(memory.Initialize(pid));
+  ProcessMemoryLinux memory(&connection);
 
   LinuxVMAddress platform_addr;
   ASSERT_TRUE(aux.GetValue(AT_PLATFORM, &platform_addr));
diff --git a/util/linux/direct_ptrace_connection.cc b/util/linux/direct_ptrace_connection.cc
index 8b55205..5da0147 100644
--- a/util/linux/direct_ptrace_connection.cc
+++ b/util/linux/direct_ptrace_connection.cc
@@ -39,10 +39,6 @@
   }
   pid_ = pid;
 
-  if (!memory_.Initialize(pid)) {
-    return false;
-  }
-
   INITIALIZATION_STATE_SET_VALID(initialized_);
   return true;
 }
@@ -79,7 +75,10 @@
 
 ProcessMemory* DirectPtraceConnection::Memory() {
   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
-  return &memory_;
+  if (!memory_) {
+    memory_ = std::make_unique<ProcessMemoryLinux>(this);
+  }
+  return memory_.get();
 }
 
 bool DirectPtraceConnection::Threads(std::vector<pid_t>* threads) {
@@ -87,4 +86,10 @@
   return ReadThreadIDs(pid_, threads);
 }
 
+ssize_t DirectPtraceConnection::ReadUpTo(VMAddress address,
+                                         size_t size,
+                                         void* buffer) {
+  return ptracer_.ReadUpTo(pid_, address, size, static_cast<char*>(buffer));
+}
+
 }  // namespace crashpad
diff --git a/util/linux/direct_ptrace_connection.h b/util/linux/direct_ptrace_connection.h
index 10f8370..99ad233 100644
--- a/util/linux/direct_ptrace_connection.h
+++ b/util/linux/direct_ptrace_connection.h
@@ -57,10 +57,11 @@
                         std::string* contents) override;
   ProcessMemory* Memory() override;
   bool Threads(std::vector<pid_t>* threads) override;
+  ssize_t ReadUpTo(VMAddress, size_t size, void* buffer) override;
 
  private:
   std::vector<std::unique_ptr<ScopedPtraceAttach>> attachments_;
-  ProcessMemoryLinux memory_;
+  std::unique_ptr<ProcessMemory> memory_;
   pid_t pid_;
   Ptracer ptracer_;
   InitializationStateDcheck initialized_;
diff --git a/util/linux/ptrace_broker_test.cc b/util/linux/ptrace_broker_test.cc
index 341f2c8..2012df3 100644
--- a/util/linux/ptrace_broker_test.cc
+++ b/util/linux/ptrace_broker_test.cc
@@ -151,8 +151,7 @@
     broker_thread.Start();
 
     PtraceClient client;
-    ASSERT_TRUE(client.Initialize(
-        client_sock.get(), ChildPID(), /* try_direct_memory= */ false));
+    ASSERT_TRUE(client.Initialize(client_sock.get(), ChildPID()));
 
     EXPECT_EQ(client.GetProcessID(), ChildPID());
 
@@ -177,32 +176,26 @@
     ASSERT_TRUE(client.GetThreadInfo(child2_tid, &info2));
     EXPECT_EQ(info2.thread_specific_data_address, child2_tls);
 
-    ProcessMemory* memory = client.Memory();
-    ASSERT_TRUE(memory);
-
-    auto buffer = std::make_unique<char[]>(mapping_.len());
-    ASSERT_TRUE(memory->Read(
-        mapping_.addr_as<VMAddress>(), mapping_.len(), buffer.get()));
     auto expected_buffer = mapping_.addr_as<char*>();
-    for (size_t index = 0; index < mapping_.len(); ++index) {
-      EXPECT_EQ(buffer[index], expected_buffer[index]);
-    }
-
     char first;
-    ASSERT_TRUE(
-        memory->Read(mapping_.addr_as<VMAddress>(), sizeof(first), &first));
+    ASSERT_EQ(
+        client.ReadUpTo(mapping_.addr_as<VMAddress>(), sizeof(first), &first),
+        1);
     EXPECT_EQ(first, expected_buffer[0]);
 
     char last;
-    ASSERT_TRUE(memory->Read(mapping_.addr_as<VMAddress>() + mapping_.len() - 1,
-                             sizeof(last),
-                             &last));
+    ASSERT_EQ(
+        client.ReadUpTo(mapping_.addr_as<VMAddress>() + mapping_.len() - 1,
+                        sizeof(last),
+                        &last),
+        1);
     EXPECT_EQ(last, expected_buffer[mapping_.len() - 1]);
 
     char unmapped;
-    EXPECT_FALSE(memory->Read(mapping_.addr_as<VMAddress>() + mapping_.len(),
+    EXPECT_EQ(client.ReadUpTo(mapping_.addr_as<VMAddress>() + mapping_.len(),
                               sizeof(unmapped),
-                              &unmapped));
+                              &unmapped),
+              -1);
 
     std::string file_root = file_dir.value() + '/';
     broker.SetFileRoot(file_root.c_str());
diff --git a/util/linux/ptrace_client.cc b/util/linux/ptrace_client.cc
index 0e9c821..cb1a1a5 100644
--- a/util/linux/ptrace_client.cc
+++ b/util/linux/ptrace_client.cc
@@ -143,7 +143,7 @@
   }
 }
 
-bool PtraceClient::Initialize(int sock, pid_t pid, bool try_direct_memory) {
+bool PtraceClient::Initialize(int sock, pid_t pid) {
   INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
   sock_ = sock;
   pid_ = pid;
@@ -166,16 +166,6 @@
   }
   is_64_bit_ = is_64_bit == ExceptionHandlerProtocol::kBoolTrue;
 
-  if (try_direct_memory) {
-    auto direct_mem = std::make_unique<ProcessMemoryLinux>();
-    if (direct_mem->Initialize(pid)) {
-      memory_.reset(direct_mem.release());
-    }
-  }
-  if (!memory_) {
-    memory_ = std::make_unique<BrokeredMemory>(this);
-  }
-
   INITIALIZATION_STATE_SET_VALID(initialized_);
   return true;
 }
@@ -260,6 +250,9 @@
 
 ProcessMemory* PtraceClient::Memory() {
   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+  if (!memory_) {
+    memory_ = std::make_unique<ProcessMemoryLinux>(this);
+  }
   return memory_.get();
 }
 
@@ -308,20 +301,7 @@
   return true;
 }
 
-PtraceClient::BrokeredMemory::BrokeredMemory(PtraceClient* client)
-    : ProcessMemory(), client_(client) {}
-
-PtraceClient::BrokeredMemory::~BrokeredMemory() = default;
-
-ssize_t PtraceClient::BrokeredMemory::ReadUpTo(VMAddress address,
-                                               size_t size,
-                                               void* buffer) const {
-  return client_->ReadUpTo(address, size, buffer);
-}
-
-ssize_t PtraceClient::ReadUpTo(VMAddress address,
-                               size_t size,
-                               void* buffer) const {
+ssize_t PtraceClient::ReadUpTo(VMAddress address, size_t size, void* buffer) {
   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
   char* buffer_c = reinterpret_cast<char*>(buffer);
 
diff --git a/util/linux/ptrace_client.h b/util/linux/ptrace_client.h
index b4f27ae..896a8b4 100644
--- a/util/linux/ptrace_client.h
+++ b/util/linux/ptrace_client.h
@@ -46,11 +46,8 @@
   //!     ownership of the socket.
   //! \param[in] pid The process ID of the process to form a PtraceConnection
   //!     with.
-  //! \param[in] try_direct_memory If `true` the client will attempt to support
-  //!     memory reading operations by directly acessing the target process'
-  //!     /proc/[pid]/mem file.
   //! \return `true` on success. `false` on failure with a message logged.
-  bool Initialize(int sock, pid_t pid, bool try_direct_memory = true);
+  bool Initialize(int sock, pid_t pid);
 
   // PtraceConnection:
 
@@ -62,24 +59,9 @@
                         std::string* contents) override;
   ProcessMemory* Memory() override;
   bool Threads(std::vector<pid_t>* threads) override;
+  ssize_t ReadUpTo(VMAddress address, size_t size, void* buffer) override;
 
  private:
-  class BrokeredMemory : public ProcessMemory {
-   public:
-    explicit BrokeredMemory(PtraceClient* client);
-    ~BrokeredMemory();
-
-    ssize_t ReadUpTo(VMAddress address,
-                     size_t size,
-                     void* buffer) const override;
-
-   private:
-    PtraceClient* client_;
-
-    DISALLOW_COPY_AND_ASSIGN(BrokeredMemory);
-  };
-
-  ssize_t ReadUpTo(VMAddress address, size_t size, void* buffer) const;
   bool SendFilePath(const char* path, size_t length);
 
   std::unique_ptr<ProcessMemory> memory_;
diff --git a/util/linux/ptrace_connection.h b/util/linux/ptrace_connection.h
index 2111747..9b31d52 100644
--- a/util/linux/ptrace_connection.h
+++ b/util/linux/ptrace_connection.h
@@ -73,6 +73,20 @@
   //!     this method returns `false`, \a threads may contain a partial list of
   //!     thread IDs.
   virtual bool Threads(std::vector<pid_t>* threads) = 0;
+
+  //! \brief Copies memory from the connected process into a caller-provided
+  //!     buffer in the current process, up to a maximum number of bytes.
+  //!
+  //! \param[in] address The address, in the connected process' address space,
+  //!     of the memory region to copy.
+  //! \param[in] size The maximum size, in bytes, of the memory region to copy.
+  //!     \a buffer must be at least this size.
+  //! \param[out] buffer The buffer into which the contents of the other
+  //!     process' memory will be copied.
+  //!
+  //! \return the number of bytes copied, 0 if there is no more data to read, or
+  //!     -1 on failure with a message logged.
+  virtual ssize_t ReadUpTo(VMAddress address, size_t size, void* buffer) = 0;
 };
 
 }  // namespace crashpad
diff --git a/util/process/process_memory_linux.cc b/util/process/process_memory_linux.cc
index 1fc3c05..56ac0ec 100644
--- a/util/process/process_memory_linux.cc
+++ b/util/process/process_memory_linux.cc
@@ -27,38 +27,37 @@
 
 namespace crashpad {
 
-ProcessMemoryLinux::ProcessMemoryLinux()
-    : ProcessMemory(), mem_fd_(), pid_(-1), initialized_() {}
+ProcessMemoryLinux::ProcessMemoryLinux(PtraceConnection* connection)
+    : ProcessMemory(), mem_fd_() {
+  char path[32];
+  snprintf(path, sizeof(path), "/proc/%d/mem", connection->GetProcessID());
+  mem_fd_.reset(HANDLE_EINTR(open(path, O_RDONLY | O_NOCTTY | O_CLOEXEC)));
+  if (mem_fd_.is_valid()) {
+    read_up_to_ = [this](VMAddress address, size_t size, void* buffer) {
+      ssize_t bytes_read =
+          HANDLE_EINTR(pread64(mem_fd_.get(), buffer, size, address));
+      if (bytes_read < 0) {
+        PLOG(ERROR) << "pread64";
+      }
+      return bytes_read;
+    };
+    return;
+  }
+
+  read_up_to_ = std::bind(&PtraceConnection::ReadUpTo,
+                          connection,
+                          std::placeholders::_1,
+                          std::placeholders::_2,
+                          std::placeholders::_3);
+}
 
 ProcessMemoryLinux::~ProcessMemoryLinux() {}
 
-bool ProcessMemoryLinux::Initialize(pid_t pid) {
-  INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
-  pid_ = pid;
-  char path[32];
-  snprintf(path, sizeof(path), "/proc/%d/mem", pid_);
-  mem_fd_.reset(HANDLE_EINTR(open(path, O_RDONLY | O_NOCTTY | O_CLOEXEC)));
-  if (!mem_fd_.is_valid()) {
-    PLOG(ERROR) << "open";
-    return false;
-  }
-  INITIALIZATION_STATE_SET_VALID(initialized_);
-  return true;
-}
-
 ssize_t ProcessMemoryLinux::ReadUpTo(VMAddress address,
                                      size_t size,
                                      void* buffer) const {
-  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
-  DCHECK(mem_fd_.is_valid());
   DCHECK_LE(size, size_t{std::numeric_limits<ssize_t>::max()});
-
-  ssize_t bytes_read =
-      HANDLE_EINTR(pread64(mem_fd_.get(), buffer, size, address));
-  if (bytes_read < 0) {
-    PLOG(ERROR) << "pread64";
-  }
-  return bytes_read;
+  return read_up_to_(address, size, buffer);
 }
 
 }  // namespace crashpad
diff --git a/util/process/process_memory_linux.h b/util/process/process_memory_linux.h
index 4fe008b..1150f14 100644
--- a/util/process/process_memory_linux.h
+++ b/util/process/process_memory_linux.h
@@ -17,12 +17,13 @@
 
 #include <sys/types.h>
 
+#include <functional>
 #include <string>
 
 #include "base/files/scoped_file.h"
 #include "base/macros.h"
+#include "util/linux/ptrace_connection.h"
 #include "util/misc/address_types.h"
-#include "util/misc/initialization_state_dcheck.h"
 #include "util/process/process_memory.h"
 
 namespace crashpad {
@@ -30,26 +31,14 @@
 //! \brief Accesses the memory of another Linux process.
 class ProcessMemoryLinux final : public ProcessMemory {
  public:
-  ProcessMemoryLinux();
+  explicit ProcessMemoryLinux(PtraceConnection* connection);
   ~ProcessMemoryLinux();
 
-  //! \brief Initializes this object to read the memory of a process whose ID
-  //!     is \a pid.
-  //!
-  //! This method must be called successfully prior to calling any other method
-  //! in this class.
-  //!
-  //! \param[in] pid The process ID of a target process.
-  //!
-  //! \return `true` on success, `false` on failure with a message logged.
-  bool Initialize(pid_t pid);
-
  private:
   ssize_t ReadUpTo(VMAddress address, size_t size, void* buffer) const override;
 
+  std::function<ssize_t(VMAddress, size_t, void*)> read_up_to_;
   base::ScopedFD mem_fd_;
-  pid_t pid_;
-  InitializationStateDcheck initialized_;
 
   DISALLOW_COPY_AND_ASSIGN(ProcessMemoryLinux);
 };
diff --git a/util/process/process_memory_range_test.cc b/util/process/process_memory_range_test.cc
index a5c7afb..2e34665 100644
--- a/util/process/process_memory_range_test.cc
+++ b/util/process/process_memory_range_test.cc
@@ -23,6 +23,10 @@
 #include "util/misc/from_pointer_cast.h"
 #include "util/process/process_memory_native.h"
 
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#include "test/linux/fake_ptrace_connection.h"
+#endif
+
 namespace crashpad {
 namespace test {
 namespace {
@@ -39,8 +43,14 @@
   constexpr bool is_64_bit = false;
 #endif  // ARCH_CPU_64_BITS
 
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+  FakePtraceConnection connection;
+  ASSERT_TRUE(connection.Initialize(GetSelfProcess()));
+  ProcessMemoryLinux memory(&connection);
+#else
   ProcessMemoryNative memory;
   ASSERT_TRUE(memory.Initialize(GetSelfProcess()));
+#endif  // OS_ANDROID || OS_LINUX || OS_CHROMEOS
 
   ProcessMemoryRange range;
   ASSERT_TRUE(range.Initialize(&memory, is_64_bit));
diff --git a/util/process/process_memory_sanitized_test.cc b/util/process/process_memory_sanitized_test.cc
index 1a7f9c9..b88eab1 100644
--- a/util/process/process_memory_sanitized_test.cc
+++ b/util/process/process_memory_sanitized_test.cc
@@ -19,13 +19,23 @@
 #include "util/misc/from_pointer_cast.h"
 #include "util/process/process_memory_native.h"
 
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#include "test/linux/fake_ptrace_connection.h"
+#endif
+
 namespace crashpad {
 namespace test {
 namespace {
 
 TEST(ProcessMemorySanitized, DenyDisallowedMemory) {
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+  FakePtraceConnection connection;
+  ASSERT_TRUE(connection.Initialize(GetSelfProcess()));
+  ProcessMemoryLinux memory(&connection);
+#else
   ProcessMemoryNative memory;
   ASSERT_TRUE(memory.Initialize(GetSelfProcess()));
+#endif  // OS_ANDROID || OS_LINUX || OS_CHROMEOS
 
   char c = 42;
   char out;
@@ -41,8 +51,14 @@
 }
 
 TEST(ProcessMemorySanitized, AllowedMemory) {
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+  FakePtraceConnection connection;
+  ASSERT_TRUE(connection.Initialize(GetSelfProcess()));
+  ProcessMemoryLinux memory(&connection);
+#else
   ProcessMemoryNative memory;
   ASSERT_TRUE(memory.Initialize(GetSelfProcess()));
+#endif  // OS_ANDROID || OS_LINUX || OS_CHROMEOS
 
   char str[4] = "ABC";
   char out[4];
diff --git a/util/process/process_memory_test.cc b/util/process/process_memory_test.cc
index 7faa400..6857b04 100644
--- a/util/process/process_memory_test.cc
+++ b/util/process/process_memory_test.cc
@@ -34,6 +34,11 @@
 #include "test/mac/mach_multiprocess.h"
 #endif  // defined(OS_APPLE)
 
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#include "test/linux/fake_ptrace_connection.h"
+#include "util/linux/direct_ptrace_connection.h"
+#endif  // OS_ANDROID || OS_LINUX || OS_CHROMEOS
+
 namespace crashpad {
 namespace test {
 namespace {
@@ -148,8 +153,14 @@
   }
 
   void DoTest(ProcessType process, size_t region_size, VMAddress address) {
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+    FakePtraceConnection connection;
+    ASSERT_TRUE(connection.Initialize(process));
+    ProcessMemoryLinux memory(&connection);
+#else
     ProcessMemoryNative memory;
     ASSERT_TRUE(memory.Initialize(process));
+#endif  // OS_ANDROID || OS_LINUX || OS_CHROMEOS
 
     std::unique_ptr<char[]> result(new char[region_size]);
 
@@ -328,8 +339,14 @@
               VMAddress local_empty_address,
               VMAddress local_short_address,
               VMAddress long_string_address) {
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+    FakePtraceConnection connection;
+    ASSERT_TRUE(connection.Initialize(process));
+    ProcessMemoryLinux memory(&connection);
+#else
     ProcessMemoryNative memory;
     ASSERT_TRUE(memory.Initialize(process));
+#endif  // OS_ANDROID || OS_LINUX || OS_CHROMEOS
 
     Compare(memory, const_empty_address, kConstCharEmpty);
     Compare(memory, const_short_address, kConstCharShort);
@@ -399,8 +416,14 @@
   }
 
   void DoTest(ProcessType process, VMAddress address) {
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+    DirectPtraceConnection connection;
+    ASSERT_TRUE(connection.Initialize(process));
+    ProcessMemoryLinux memory(&connection);
+#else
     ProcessMemoryNative memory;
     ASSERT_TRUE(memory.Initialize(process));
+#endif  // OS_ANDROID || OS_LINUX || OS_CHROMEOS
 
     VMAddress page_addr1 = address;
     VMAddress page_addr2 = page_addr1 + base::GetPageSize();
@@ -525,8 +548,14 @@
 
   void DoTest(ProcessType process,
               const std::vector<StringDataInChildProcess>& strings) {
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+    DirectPtraceConnection connection;
+    ASSERT_TRUE(connection.Initialize(process));
+    ProcessMemoryLinux memory(&connection);
+#else
     ProcessMemoryNative memory;
     ASSERT_TRUE(memory.Initialize(process));
+#endif  // OS_ANDROID || OS_LINUX || OS_CHROMEOS
 
     std::string result;
     result.reserve(kChildProcessStringLength + 1);