Reland "Mac: Record via metrics the number of open FDs and the soft FD limit."

This is a reland of a72c20e443285e06e064e67ec754d4f60d4e6d22

Fixes ProcessMetricsTest.GetChildOpenFdCount to not close guarded
FDs on macOS 10.10 and 10.11.

Original change's description:
> Mac: Record via metrics the number of open FDs and the soft FD limit.
>
> The histograms already exist on Linux, CrOS, and Android, so this simply
> wires up the values for macOS.
>
> In addition, this enables the FD count column in the Task Manager, since
> the data are now readily available.
>
> Bug: 714614
> Change-Id: I05f8063e8d89d3c6cdc68062bf4e591d3af9559c
> Reviewed-on: https://chromium-review.googlesource.com/c/1423339
> Reviewed-by: Ahmed Fakhry <afakhry@chromium.org>
> Reviewed-by: Nico Weber <thakis@chromium.org>
> Reviewed-by: Mark Mentovai <mark@chromium.org>
> Commit-Queue: Robert Sesek <rsesek@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#624881}

Tbr: thakis@chromium.org
Bug: 714614
Change-Id: Icc79aa88826e9079845f06ed6c3f52139713b404
Reviewed-on: https://chromium-review.googlesource.com/c/1430719
Commit-Queue: Robert Sesek <rsesek@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
Reviewed-by: Ahmed Fakhry <afakhry@chromium.org>
Cr-Commit-Position: refs/heads/master@{#625329}
diff --git a/base/process/process_metrics.h b/base/process/process_metrics.h
index a8afb18..3bba9aa 100644
--- a/base/process/process_metrics.h
+++ b/base/process/process_metrics.h
@@ -189,7 +189,7 @@
   // process since process start.
   uint64_t GetCumulativeDiskUsageInBytes();
 
-#if defined(OS_LINUX) || defined(OS_AIX) || defined(OS_ANDROID)
+#if defined(OS_POSIX)
   // Returns the number of file descriptors currently open by the process, or
   // -1 on error.
   int GetOpenFdCount() const;
@@ -197,7 +197,7 @@
   // Returns the soft limit of file descriptors that can be opened by the
   // process, or -1 on error.
   int GetOpenFdSoftLimit() const;
-#endif  // defined(OS_LINUX) || defined(OS_AIX) || defined(OS_ANDROID)
+#endif  // defined(OS_POSIX)
 
 #if defined(OS_LINUX) || defined(OS_ANDROID)
   // Bytes of swap as reported by /proc/[pid]/status.
diff --git a/base/process/process_metrics_mac.cc b/base/process/process_metrics_mac.cc
index ef7f8ae..cbb5e93 100644
--- a/base/process/process_metrics_mac.cc
+++ b/base/process/process_metrics_mac.cc
@@ -4,6 +4,7 @@
 
 #include "base/process/process_metrics.h"
 
+#include <libproc.h>
 #include <mach/mach.h>
 #include <mach/mach_vm.h>
 #include <mach/shared_region.h>
@@ -193,6 +194,34 @@
   return CalculateIdleWakeupsPerSecond(power_info_data.task_interrupt_wakeups);
 }
 
+int ProcessMetrics::GetOpenFdCount() const {
+  // In order to get a true count of the open number of FDs, PROC_PIDLISTFDS
+  // is used. This is done twice: first to get the appropriate size of a
+  // buffer, and then secondly to fill the buffer with the actual FD info.
+  //
+  // The buffer size returned in the first call is an estimate, based on the
+  // number of allocated fileproc structures in the kernel. This number can be
+  // greater than the actual number of open files, since the structures are
+  // allocated in slabs. The value returned in proc_bsdinfo::pbi_nfiles is
+  // also the number of allocated fileprocs, not the number in use.
+  //
+  // However, the buffer size returned in the second call is an accurate count
+  // of the open number of descriptors. The contents of the buffer are unused.
+  int rv = proc_pidinfo(process_, PROC_PIDLISTFDS, 0, nullptr, 0);
+  if (rv < 0)
+    return -1;
+
+  std::unique_ptr<char[]> buffer(new char[rv]);
+  rv = proc_pidinfo(process_, PROC_PIDLISTFDS, 0, buffer.get(), rv);
+  if (rv < 0)
+    return -1;
+  return rv / PROC_PIDLISTFD_SIZE;
+}
+
+int ProcessMetrics::GetOpenFdSoftLimit() const {
+  return GetMaxFds();
+}
+
 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
   return false;
 }
diff --git a/base/process/process_metrics_unittest.cc b/base/process/process_metrics_unittest.cc
index eec66b887..791fa23 100644
--- a/base/process/process_metrics_unittest.cc
+++ b/base/process/process_metrics_unittest.cc
@@ -19,6 +19,7 @@
 #include "base/macros.h"
 #include "base/memory/shared_memory.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "base/system/sys_info.h"
 #include "base/test/multiprocess_test.h"
 #include "base/threading/thread.h"
@@ -519,7 +520,7 @@
 }
 #endif  // defined(OS_LINUX)
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || (defined(OS_MACOSX) && !defined(OS_IOS))
 namespace {
 
 // Keep these in sync so the GetChildOpenFdCount test can refer to correct test
@@ -529,8 +530,15 @@
 
 // Command line flag name and file name used for synchronization.
 const char kTempDirFlag[] = "temp-dir";
+
+const char kSignalReady[] = "ready";
+const char kSignalReadyAck[] = "ready-ack";
+const char kSignalOpened[] = "opened";
+const char kSignalOpenedAck[] = "opened-ack";
 const char kSignalClosed[] = "closed";
 
+const int kChildNumFilesToOpen = 100;
+
 bool SignalEvent(const FilePath& signal_dir, const char* signal_file) {
   File file(signal_dir.AppendASCII(signal_file),
             File::FLAG_CREATE | File::FLAG_WRITE);
@@ -556,9 +564,20 @@
   const FilePath temp_path = command_line->GetSwitchValuePath(kTempDirFlag);
   CHECK(DirectoryExists(temp_path));
 
-  // Try to close all the file descriptors, so the open count goes to 0.
-  for (size_t i = 0; i < 1000; ++i)
-    close(i);
+  CHECK(SignalEvent(temp_path, kSignalReady));
+  WaitForEvent(temp_path, kSignalReadyAck);
+
+  std::vector<File> files;
+  for (int i = 0; i < kChildNumFilesToOpen; ++i) {
+    files.emplace_back(temp_path.AppendASCII(StringPrintf("file.%d", i)),
+                       File::FLAG_CREATE | File::FLAG_WRITE);
+  }
+
+  CHECK(SignalEvent(temp_path, kSignalOpened));
+  WaitForEvent(temp_path, kSignalOpenedAck);
+
+  files.clear();
+
   CHECK(SignalEvent(temp_path, kSignalClosed));
 
   // Wait to be terminated.
@@ -578,30 +597,56 @@
   Process child = SpawnMultiProcessTestChild(
       ChildMainString, child_command_line, LaunchOptions());
   ASSERT_TRUE(child.IsValid());
+
+  WaitForEvent(temp_path, kSignalReady);
+
+  std::unique_ptr<ProcessMetrics> metrics =
+#if defined(OS_MACOSX)
+      ProcessMetrics::CreateProcessMetrics(child.Handle(), nullptr);
+#else
+      ProcessMetrics::CreateProcessMetrics(child.Handle());
+#endif  // defined(OS_MACOSX)
+
+  const int fd_count = metrics->GetOpenFdCount();
+  EXPECT_GE(fd_count, 0);
+
+  ASSERT_TRUE(SignalEvent(temp_path, kSignalReadyAck));
+  WaitForEvent(temp_path, kSignalOpened);
+
+  EXPECT_EQ(fd_count + kChildNumFilesToOpen, metrics->GetOpenFdCount());
+  ASSERT_TRUE(SignalEvent(temp_path, kSignalOpenedAck));
+
   WaitForEvent(temp_path, kSignalClosed);
 
-  std::unique_ptr<ProcessMetrics> metrics(
-      ProcessMetrics::CreateProcessMetrics(child.Handle()));
-  EXPECT_EQ(0, metrics->GetOpenFdCount());
+  EXPECT_EQ(fd_count, metrics->GetOpenFdCount());
+
   ASSERT_TRUE(child.Terminate(0, true));
 }
-#endif  // defined(OS_LINUX)
-
-#if defined(OS_ANDROID) || defined(OS_LINUX)
 
 TEST(ProcessMetricsTest, GetOpenFdCount) {
-  std::unique_ptr<base::ProcessMetrics> metrics(
-      base::ProcessMetrics::CreateProcessMetrics(
-          base::GetCurrentProcessHandle()));
+  base::ProcessHandle process = base::GetCurrentProcessHandle();
+  std::unique_ptr<base::ProcessMetrics> metrics =
+#if defined(OS_MACOSX)
+      ProcessMetrics::CreateProcessMetrics(process, nullptr);
+#else
+      ProcessMetrics::CreateProcessMetrics(process);
+#endif  // defined(OS_MACOSX)
+
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
   int fd_count = metrics->GetOpenFdCount();
   EXPECT_GT(fd_count, 0);
-  ScopedFILE file(fopen("/proc/self/statm", "r"));
-  EXPECT_TRUE(file);
+  File file(temp_dir.GetPath().AppendASCII("file"),
+            File::FLAG_CREATE | File::FLAG_WRITE);
   int new_fd_count = metrics->GetOpenFdCount();
   EXPECT_GT(new_fd_count, 0);
   EXPECT_EQ(new_fd_count, fd_count + 1);
 }
 
+#endif  // defined(OS_LINUX) || (defined(OS_MACOSX) && !defined(OS_IOS))
+
+#if defined(OS_ANDROID) || defined(OS_LINUX)
 TEST(ProcessMetricsTestLinux, GetPageFaultCounts) {
   std::unique_ptr<base::ProcessMetrics> process_metrics(
       base::ProcessMetrics::CreateProcessMetrics(
diff --git a/chrome/browser/memory_details_mac.cc b/chrome/browser/memory_details_mac.cc
index 2bebccc..b9d67ca 100644
--- a/chrome/browser/memory_details_mac.cc
+++ b/chrome/browser/memory_details_mac.cc
@@ -50,6 +50,13 @@
   info.product_name = base::ASCIIToUTF16(version_info::GetProductName());
   info.version = base::ASCIIToUTF16(version_info::GetVersionNumber());
 
+  // A PortProvider is not necessary to acquire information about the number
+  // of open file descriptors.
+  std::unique_ptr<base::ProcessMetrics> metrics(
+      base::ProcessMetrics::CreateProcessMetrics(pid, nullptr));
+  info.num_open_fds = metrics->GetOpenFdCount();
+  info.open_fds_soft_limit = metrics->GetOpenFdSoftLimit();
+
   // Check if this is one of the child processes whose data was already
   // collected and exists in |child_data|.
   for (const ProcessMemoryInformation& child : child_info) {
diff --git a/chrome/browser/task_manager/sampling/task_group.cc b/chrome/browser/task_manager/sampling/task_group.cc
index ac096caad..6a9adda5 100644
--- a/chrome/browser/task_manager/sampling/task_group.cc
+++ b/chrome/browser/task_manager/sampling/task_group.cc
@@ -33,9 +33,9 @@
 #if defined(OS_WIN)
     REFRESH_TYPE_START_TIME | REFRESH_TYPE_CPU_TIME |
 #endif  // defined(OS_WIN)
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
     REFRESH_TYPE_FD_COUNT |
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
 #if BUILDFLAG(ENABLE_NACL)
     REFRESH_TYPE_NACL |
 #endif  // BUILDFLAG(ENABLE_NACL)
@@ -112,9 +112,9 @@
 #if BUILDFLAG(ENABLE_NACL)
       nacl_debug_stub_port_(nacl::kGdbDebugStubPortUnknown),
 #endif  // BUILDFLAG(ENABLE_NACL)
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
       open_fd_count_(-1),
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
       idle_wakeups_per_second_(-1),
       gpu_memory_has_duplicates_(false),
       is_backgrounded_(false),
@@ -128,10 +128,10 @@
                    weak_ptr_factory_.GetWeakPtr()),
         base::Bind(&TaskGroup::OnIdleWakeupsRefreshDone,
                    weak_ptr_factory_.GetWeakPtr()),
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
         base::Bind(&TaskGroup::OnOpenFdCountRefreshDone,
                    weak_ptr_factory_.GetWeakPtr()),
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
         base::Bind(&TaskGroup::OnProcessPriorityDone,
                    weak_ptr_factory_.GetWeakPtr()));
 
@@ -296,14 +296,14 @@
 }
 #endif  // BUILDFLAG(ENABLE_NACL)
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
 void TaskGroup::OnOpenFdCountRefreshDone(int open_fd_count) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   open_fd_count_ = open_fd_count;
   OnBackgroundRefreshTypeFinished(REFRESH_TYPE_FD_COUNT);
 }
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
 
 void TaskGroup::OnCpuRefreshDone(double cpu_usage) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/chrome/browser/task_manager/sampling/task_group.h b/chrome/browser/task_manager/sampling/task_group.h
index 16661eb5..9ada18b 100644
--- a/chrome/browser/task_manager/sampling/task_group.h
+++ b/chrome/browser/task_manager/sampling/task_group.h
@@ -106,9 +106,9 @@
   int nacl_debug_stub_port() const { return nacl_debug_stub_port_; }
 #endif  // BUILDFLAG(ENABLE_NACL)
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
   int open_fd_count() const { return open_fd_count_; }
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
 
   int idle_wakeups_per_second() const { return idle_wakeups_per_second_; }
  private:
@@ -121,9 +121,9 @@
   void RefreshNaClDebugStubPort(int child_process_unique_id);
   void OnRefreshNaClDebugStubPortDone(int port);
 #endif
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
   void OnOpenFdCountRefreshDone(int open_fd_count);
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
 
   void OnCpuRefreshDone(double cpu_usage);
   void OnSwappedMemRefreshDone(int64_t swapped_mem_bytes);
@@ -191,10 +191,10 @@
 #if BUILDFLAG(ENABLE_NACL)
   int nacl_debug_stub_port_;
 #endif  // BUILDFLAG(ENABLE_NACL)
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
   // The number of file descriptors currently open by the process.
   int open_fd_count_;
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
   int idle_wakeups_per_second_;
   bool gpu_memory_has_duplicates_;
   bool is_backgrounded_;
diff --git a/chrome/browser/task_manager/sampling/task_group_sampler.cc b/chrome/browser/task_manager/sampling/task_group_sampler.cc
index c838e91..b9c9f4b3 100644
--- a/chrome/browser/task_manager/sampling/task_group_sampler.cc
+++ b/chrome/browser/task_manager/sampling/task_group_sampler.cc
@@ -42,9 +42,9 @@
     const OnCpuRefreshCallback& on_cpu_refresh,
     const OnSwappedMemRefreshCallback& on_swapped_mem_refresh,
     const OnIdleWakeupsCallback& on_idle_wakeups,
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
     const OnOpenFdCountCallback& on_open_fd_count,
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
     const OnProcessPriorityCallback& on_process_priority)
     : process_(std::move(process)),
       process_metrics_(CreateProcessMetrics(process_.Handle())),
@@ -52,9 +52,9 @@
       on_cpu_refresh_callback_(on_cpu_refresh),
       on_swapped_mem_refresh_callback_(on_swapped_mem_refresh),
       on_idle_wakeups_callback_(on_idle_wakeups),
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
       on_open_fd_count_callback_(on_open_fd_count),
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
       on_process_priority_callback_(on_process_priority) {
   DCHECK(blocking_pool_runner.get());
 
@@ -96,7 +96,7 @@
   }
 #endif  // defined(OS_MACOSX) || defined(OS_LINUX)
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
   if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_FD_COUNT,
                                                     refresh_flags)) {
     base::PostTaskAndReplyWithResult(
@@ -105,7 +105,7 @@
         base::Bind(&TaskGroupSampler::RefreshOpenFdCount, this),
         on_open_fd_count_callback_);
   }
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
 
   if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_PRIORITY,
                                                     refresh_flags)) {
@@ -144,13 +144,13 @@
   return process_metrics_->GetIdleWakeupsPerSecond();
 }
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
 int TaskGroupSampler::RefreshOpenFdCount() {
   DCHECK(worker_pool_sequenced_checker_.CalledOnValidSequence());
 
   return process_metrics_->GetOpenFdCount();
 }
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
 
 bool TaskGroupSampler::RefreshProcessPriority() {
   DCHECK(worker_pool_sequenced_checker_.CalledOnValidSequence());
diff --git a/chrome/browser/task_manager/sampling/task_group_sampler.h b/chrome/browser/task_manager/sampling/task_group_sampler.h
index c0c6241..57d33d1 100644
--- a/chrome/browser/task_manager/sampling/task_group_sampler.h
+++ b/chrome/browser/task_manager/sampling/task_group_sampler.h
@@ -32,9 +32,9 @@
   using OnCpuRefreshCallback = base::Callback<void(double)>;
   using OnSwappedMemRefreshCallback = base::Callback<void(int64_t)>;
   using OnIdleWakeupsCallback = base::Callback<void(int)>;
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
   using OnOpenFdCountCallback = base::Callback<void(int)>;
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
   using OnProcessPriorityCallback = base::Callback<void(bool)>;
 
   TaskGroupSampler(
@@ -43,9 +43,9 @@
       const OnCpuRefreshCallback& on_cpu_refresh,
       const OnSwappedMemRefreshCallback& on_memory_refresh,
       const OnIdleWakeupsCallback& on_idle_wakeups,
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
       const OnOpenFdCountCallback& on_open_fd_count,
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
       const OnProcessPriorityCallback& on_process_priority);
 
   // Refreshes the expensive process' stats (CPU usage, memory usage, and idle
@@ -60,9 +60,9 @@
   double RefreshCpuUsage();
   int64_t RefreshSwappedMem();
   int RefreshIdleWakeupsPerSecond();
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
   int RefreshOpenFdCount();
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
   bool RefreshProcessPriority();
 
   // The process that holds the handle that we own so that we can use it for
@@ -80,9 +80,9 @@
   const OnCpuRefreshCallback on_cpu_refresh_callback_;
   const OnSwappedMemRefreshCallback on_swapped_mem_refresh_callback_;
   const OnIdleWakeupsCallback on_idle_wakeups_callback_;
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
   const OnOpenFdCountCallback on_open_fd_count_callback_;
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
   const OnProcessPriorityCallback on_process_priority_callback_;
 
   // To assert we're running on the correct thread.
diff --git a/chrome/browser/task_manager/sampling/task_manager_impl.cc b/chrome/browser/task_manager/sampling/task_manager_impl.cc
index fcf6477..f55de38 100644
--- a/chrome/browser/task_manager/sampling/task_manager_impl.cc
+++ b/chrome/browser/task_manager/sampling/task_manager_impl.cc
@@ -15,6 +15,7 @@
 #include "base/command_line.h"
 #include "base/containers/adapters.h"
 #include "base/task/post_task.h"
+#include "build/build_config.h"
 #include "chrome/browser/task_manager/providers/browser_process_task_provider.h"
 #include "chrome/browser/task_manager/providers/child_process_task_provider.h"
 #include "chrome/browser/task_manager/providers/fallback_task_provider.h"
@@ -206,11 +207,11 @@
 }
 
 int TaskManagerImpl::GetOpenFdCount(TaskId task_id) const {
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
   return GetTaskGroupByTaskId(task_id)->open_fd_count();
 #else
   return -1;
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
 }
 
 bool TaskManagerImpl::IsTaskOnBackgroundedProcess(TaskId task_id) const {
diff --git a/chrome/browser/task_manager/task_manager_observer.h b/chrome/browser/task_manager/task_manager_observer.h
index dfb6814..60b510c 100644
--- a/chrome/browser/task_manager/task_manager_observer.h
+++ b/chrome/browser/task_manager/task_manager_observer.h
@@ -43,11 +43,11 @@
   // or backgrounded.
   REFRESH_TYPE_PRIORITY = 1 << 13,
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
   // For observers interested in getting the number of open file descriptors of
   // processes.
   REFRESH_TYPE_FD_COUNT = 1 << 14,
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
 
   REFRESH_TYPE_KEEPALIVE_COUNT = 1 << 15,
   REFRESH_TYPE_MEMORY_FOOTPRINT = 1 << 16,
diff --git a/chrome/browser/ui/task_manager/task_manager_columns.cc b/chrome/browser/ui/task_manager/task_manager_columns.cc
index 643fc3f..b0fc692 100644
--- a/chrome/browser/ui/task_manager/task_manager_columns.cc
+++ b/chrome/browser/ui/task_manager/task_manager_columns.cc
@@ -93,10 +93,10 @@
      base::size("100000") * kCharWidth, -1, true, false, false},
 #endif
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
     {IDS_TASK_MANAGER_OPEN_FD_COUNT_COLUMN, ui::TableColumn::RIGHT, -1, 0,
      base::size("999") * kCharWidth, -1, true, false, false},
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
     {IDS_TASK_MANAGER_PROCESS_PRIORITY_COLUMN, ui::TableColumn::LEFT, -1, 0,
      base::size("background") * kCharWidth, -1, true, true, false},
     {IDS_TASK_MANAGER_KEEPALIVE_COUNT_COLUMN, ui::TableColumn::RIGHT, -1, 0,
diff --git a/chrome/browser/ui/task_manager/task_manager_table_model.cc b/chrome/browser/ui/task_manager/task_manager_table_model.cc
index 9910637..19cb421c 100644
--- a/chrome/browser/ui/task_manager/task_manager_table_model.cc
+++ b/chrome/browser/ui/task_manager/task_manager_table_model.cc
@@ -430,13 +430,13 @@
           ? stringifier_->backgrounded_string()
           : stringifier_->foregrounded_string();
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
     case IDS_TASK_MANAGER_OPEN_FD_COUNT_COLUMN: {
       const int fd_count = observed_task_manager()->GetOpenFdCount(tasks_[row]);
       return fd_count >= 0 ? base::FormatNumber(fd_count)
                            : stringifier_->n_a_string();
     }
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
 
     case IDS_TASK_MANAGER_KEEPALIVE_COUNT_COLUMN: {
       return stringifier_->GetKeepaliveCountText(
@@ -590,7 +590,7 @@
       return BooleanCompare(is_proc1_bg, is_proc2_bg);
     }
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
     case IDS_TASK_MANAGER_OPEN_FD_COUNT_COLUMN: {
       const int proc1_fd_count =
           observed_task_manager()->GetOpenFdCount(tasks_[row1]);
@@ -598,7 +598,7 @@
           observed_task_manager()->GetOpenFdCount(tasks_[row2]);
       return ValueCompare(proc1_fd_count, proc2_fd_count);
     }
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
 
     default:
       NOTREACHED();
@@ -760,11 +760,11 @@
       type = REFRESH_TYPE_KEEPALIVE_COUNT;
       break;
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_MACOSX)
     case IDS_TASK_MANAGER_OPEN_FD_COUNT_COLUMN:
       type = REFRESH_TYPE_FD_COUNT;
       break;
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
 
     default:
       NOTREACHED();