Create MemoryPressure component.

This is the first CL in the refactoring of base/memory/memory_pressure_*. Futher CLs will introduce calculators for each platform, the notification and UMA reporting logic.

BUG=520962

Review URL: https://codereview.chromium.org/1293873002

Cr-Commit-Position: refs/heads/master@{#345081}
diff --git a/components/BUILD.gn b/components/BUILD.gn
index dde6837..7d2729b 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -61,6 +61,7 @@
     "//components/language_usage_metrics",
     "//components/leveldb_proto",
     "//components/login",
+    "//components/memory_pressure",
     "//components/metrics",
     "//components/mime_util",
     "//components/navigation_interception",
@@ -333,6 +334,7 @@
     "//components/keyed_service/core:unit_tests",
     "//components/leveldb_proto:unit_tests",
     "//components/login:unit_tests",
+    "//components/memory_pressure:unit_tests",
     "//components/metrics:unit_tests",
     "//components/mime_util:unit_tests",
     "//components/offline_pages:unit_tests",
diff --git a/components/OWNERS b/components/OWNERS
index 47bd329..f4f3813 100644
--- a/components/OWNERS
+++ b/components/OWNERS
@@ -150,6 +150,10 @@
 per-file login*[email protected]
 per-file login*[email protected]
 
+per-file memory_pressure*[email protected]
+per-file memory_pressure*[email protected]
+per-file memory_pressure*[email protected]
+
 per-file metrics*[email protected]
 per-file metrics*[email protected]
 per-file metrics*[email protected]
diff --git a/components/components.gyp b/components/components.gyp
index 630c5e6..9990cbf 100644
--- a/components/components.gyp
+++ b/components/components.gyp
@@ -42,6 +42,7 @@
     'language_usage_metrics.gypi',
     'leveldb_proto.gypi',
     'login.gypi',
+    'memory_pressure.gypi',
     'metrics.gypi',
     'navigation_metrics.gypi',
     'network_hints.gypi',
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 4e4a6bc..f40253e 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -298,6 +298,12 @@
     'login_unittest_sources': [
       'login/screens/screen_context_unittest.cc',
     ],
+    'memory_pressure_unittest_sources': [
+      'memory_pressure/direct_memory_pressure_calculator_win_unittest.cc',
+      'memory_pressure/filtered_memory_pressure_calculator_unittest.cc',
+      'memory_pressure/test_memory_pressure_calculator.cc',
+      'memory_pressure/test_memory_pressure_calculator.h',
+    ],
     'metrics_unittest_sources': [
       'metrics/call_stack_profile_metrics_provider_unittest.cc',
       'metrics/compression_utils_unittest.cc',
@@ -763,6 +769,7 @@
         '<@(language_usage_metrics_unittest_sources)',
         '<@(leveldb_proto_unittest_sources)',
         '<@(login_unittest_sources)',
+        '<@(memory_pressure_unittest_sources)',
         '<@(metrics_unittest_sources)',
         '<@(mime_util_unittest_sources)',
         '<@(network_time_unittest_sources)',
@@ -868,6 +875,7 @@
         'components.gyp:leveldb_proto',
         'components.gyp:leveldb_proto_test_support',
         'components.gyp:login',
+        'components.gyp:memory_pressure',
         'components.gyp:metrics',
         'components.gyp:metrics_gpu',
         'components.gyp:metrics_net',
diff --git a/components/memory_pressure.gypi b/components/memory_pressure.gypi
new file mode 100644
index 0000000..40fb726
--- /dev/null
+++ b/components/memory_pressure.gypi
@@ -0,0 +1,29 @@
+# Copyright 2015 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.
+
+{
+  'targets': [
+    {
+      # GN version: //components/memory_pressure
+      'target_name': 'memory_pressure',
+      'type': 'static_library',
+      'include_dirs': [
+        '..',
+      ],
+      'dependencies': [
+        '../base/base.gyp:base',
+      ],
+      'sources': [
+        'memory_pressure/direct_memory_pressure_calculator.cc',
+        'memory_pressure/direct_memory_pressure_calculator.h',
+        'memory_pressure/direct_memory_pressure_calculator_win.cc',
+        'memory_pressure/filtered_memory_pressure_calculator.cc',
+        'memory_pressure/filtered_memory_pressure_calculator.h',
+        'memory_pressure/memory_pressure_calculator.h',
+        'memory_pressure/memory_pressure_listener.cc',
+        'memory_pressure/memory_pressure_listener.h',
+      ],
+    },
+  ],
+}
diff --git a/components/memory_pressure/BUILD.gn b/components/memory_pressure/BUILD.gn
new file mode 100644
index 0000000..3828f48
--- /dev/null
+++ b/components/memory_pressure/BUILD.gn
@@ -0,0 +1,37 @@
+# Copyright 2015 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.
+
+# GYP version: components/memory_pressure.gypi:memory_pressure
+source_set("memory_pressure") {
+  sources = [
+    "direct_memory_pressure_calculator.cc",
+    "direct_memory_pressure_calculator.h",
+    "direct_memory_pressure_calculator_win.cc",
+    "filtered_memory_pressure_calculator.cc",
+    "filtered_memory_pressure_calculator.h",
+    "memory_pressure_calculator.h",
+    "memory_pressure_listener.cc",
+    "memory_pressure_listener.h",
+  ]
+
+  deps = [
+    "//base",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "direct_memory_pressure_calculator_win_unittest.cc",
+    "filtered_memory_pressure_calculator_unittest.cc",
+    "test_memory_pressure_calculator.cc",
+    "test_memory_pressure_calculator.h",
+  ]
+
+  deps = [
+    ":memory_pressure",
+    "//base/test:test_support",
+    "//testing/gtest",
+  ]
+}
diff --git a/components/memory_pressure/DEPS b/components/memory_pressure/DEPS
new file mode 100644
index 0000000..5cd0867
--- /dev/null
+++ b/components/memory_pressure/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+base",
+]
diff --git a/components/memory_pressure/OWNERS b/components/memory_pressure/OWNERS
new file mode 100644
index 0000000..1f457502
--- /dev/null
+++ b/components/memory_pressure/OWNERS
@@ -0,0 +1,3 @@
[email protected]
[email protected]
[email protected]
diff --git a/components/memory_pressure/direct_memory_pressure_calculator.cc b/components/memory_pressure/direct_memory_pressure_calculator.cc
new file mode 100644
index 0000000..88b5794c
--- /dev/null
+++ b/components/memory_pressure/direct_memory_pressure_calculator.cc
@@ -0,0 +1,18 @@
+// Copyright 2015 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 "components/memory_pressure/direct_memory_pressure_calculator.h"
+
+namespace memory_pressure {
+
+#if defined(MEMORY_PRESSURE_IS_POLLING)
+
+bool DirectMemoryPressureCalculator::GetSystemMemoryInfo(
+    base::SystemMemoryInfoKB* mem_info) const {
+  return base::GetSystemMemoryInfo(mem_info);
+}
+
+#endif  // defined(MEMORY_PRESSURE_IS_POLLING)
+
+}  // namespace memory_pressure
diff --git a/components/memory_pressure/direct_memory_pressure_calculator.h b/components/memory_pressure/direct_memory_pressure_calculator.h
new file mode 100644
index 0000000..98d3e169
--- /dev/null
+++ b/components/memory_pressure/direct_memory_pressure_calculator.h
@@ -0,0 +1,77 @@
+// Copyright 2015 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 COMPONENTS_MEMORY_PRESSURE_DIRECT_MEMORY_PRESSURE_CALCULATOR_H_
+#define COMPONENTS_MEMORY_PRESSURE_DIRECT_MEMORY_PRESSURE_CALCULATOR_H_
+
+#include "components/memory_pressure/memory_pressure_calculator.h"
+
+#include "base/process/process_metrics.h"
+
+namespace memory_pressure {
+
+#if defined(MEMORY_PRESSURE_IS_POLLING)
+
+// OS-specific implementation of MemoryPressureCalculator. This is only defined
+// and used on platforms that do not have native memory pressure signals
+// (ChromeOS, Linux, Windows). OSes that do have native signals simply hook into
+// the appropriate subsystem (Android, Mac OS X).
+class DirectMemoryPressureCalculator : public MemoryPressureCalculator {
+ public:
+#if defined(OS_WIN)
+  // Exposed for unittesting. See .cc file for detailed discussion of these
+  // constants.
+  static const int kLargeMemoryThresholdMb;
+  static const int kSmallMemoryDefaultModerateThresholdMb;
+  static const int kSmallMemoryDefaultCriticalThresholdMb;
+  static const int kLargeMemoryDefaultModerateThresholdMb;
+  static const int kLargeMemoryDefaultCriticalThresholdMb;
+#endif
+
+  // Default constructor. Will choose thresholds automatically based on the
+  // actual amount of system memory installed.
+  DirectMemoryPressureCalculator();
+
+  // Constructor with explicit memory thresholds. These represent the amount of
+  // free memory below which the applicable memory pressure state applies.
+  DirectMemoryPressureCalculator(int moderate_threshold_mb,
+                                 int critical_threshold_mb);
+
+  virtual ~DirectMemoryPressureCalculator() {}
+
+  // Calculates the current pressure level.
+  MemoryPressureLevel CalculateCurrentPressureLevel() override;
+
+#if defined(OS_WIN)
+  int moderate_threshold_mb() const { return moderate_threshold_mb_; }
+  int critical_threshold_mb() const { return critical_threshold_mb_; }
+#endif
+
+ private:
+  friend class TestDirectMemoryPressureCalculator;
+
+  // Gets system memory status. This is virtual as a unittesting hook and by
+  // default this invokes base::GetSystemMemoryInfo.
+  virtual bool GetSystemMemoryInfo(base::SystemMemoryInfoKB* mem_info) const;
+
+#if defined(OS_WIN)
+  // Uses GetSystemMemoryInfo to automatically infer appropriate values for
+  // moderate_threshold_mb_ and critical_threshold_mb_.
+  void InferThresholds();
+
+  // Threshold amounts of available memory that trigger pressure levels. See
+  // memory_pressure_monitor_win.cc for a discussion of reasonable values for
+  // these.
+  int moderate_threshold_mb_;
+  int critical_threshold_mb_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(DirectMemoryPressureCalculator);
+};
+
+#endif  // defined(MEMORY_PRESSURE_IS_POLLING)
+
+}  // namespace memory_pressure
+
+#endif  // COMPONENTS_MEMORY_PRESSURE_DIRECT_MEMORY_PRESSURE_CALCULATOR_H_
diff --git a/components/memory_pressure/direct_memory_pressure_calculator_win.cc b/components/memory_pressure/direct_memory_pressure_calculator_win.cc
new file mode 100644
index 0000000..25d7d7b
--- /dev/null
+++ b/components/memory_pressure/direct_memory_pressure_calculator_win.cc
@@ -0,0 +1,104 @@
+// Copyright 2015 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 "components/memory_pressure/direct_memory_pressure_calculator.h"
+
+namespace memory_pressure {
+
+namespace {
+
+static const int kKBperMB = 1024;
+
+}  // namespace
+
+// A system is considered 'high memory' if it has more than 1.5GB of system
+// memory available for use by the memory manager (not reserved for hardware
+// and drivers). This is a fuzzy version of the ~2GB discussed below.
+const int DirectMemoryPressureCalculator::kLargeMemoryThresholdMb = 1536;
+
+// These are the default thresholds used for systems with < ~2GB of physical
+// memory. Such systems have been observed to always maintain ~100MB of
+// available memory, paging until that is the case. To try to avoid paging a
+// threshold slightly above this is chosen. The moderate threshold is slightly
+// less grounded in reality and chosen as 2.5x critical.
+const int
+    DirectMemoryPressureCalculator::kSmallMemoryDefaultModerateThresholdMb =
+        500;
+const int
+    DirectMemoryPressureCalculator::kSmallMemoryDefaultCriticalThresholdMb =
+        200;
+
+// These are the default thresholds used for systems with >= ~2GB of physical
+// memory. Such systems have been observed to always maintain ~300MB of
+// available memory, paging until that is the case.
+const int
+    DirectMemoryPressureCalculator::kLargeMemoryDefaultModerateThresholdMb =
+        1000;
+const int
+    DirectMemoryPressureCalculator::kLargeMemoryDefaultCriticalThresholdMb =
+        400;
+
+DirectMemoryPressureCalculator::DirectMemoryPressureCalculator()
+    : moderate_threshold_mb_(0), critical_threshold_mb_(0) {
+  InferThresholds();
+}
+
+DirectMemoryPressureCalculator::DirectMemoryPressureCalculator(
+    int moderate_threshold_mb,
+    int critical_threshold_mb)
+    : moderate_threshold_mb_(moderate_threshold_mb),
+      critical_threshold_mb_(critical_threshold_mb) {
+  DCHECK_GE(moderate_threshold_mb_, critical_threshold_mb_);
+  DCHECK_LE(0, critical_threshold_mb_);
+}
+
+DirectMemoryPressureCalculator::MemoryPressureLevel
+DirectMemoryPressureCalculator::CalculateCurrentPressureLevel() {
+  base::SystemMemoryInfoKB mem_info = {};
+  if (!GetSystemMemoryInfo(&mem_info))
+    return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+
+  // How much system memory is actively available for use right now, in MBs.
+  int phys_free = mem_info.free / kKBperMB;
+
+  // TODO(chrisha): This should eventually care about address space pressure,
+  // but the browser process (where this is running) effectively never runs out
+  // of address space. Renderers occasionally do, but it does them no good to
+  // have the browser process monitor address space pressure. Long term,
+  // renderers should run their own address space pressure monitors and act
+  // accordingly, with the browser making cross-process decisions based on
+  // system memory pressure.
+
+  // Determine if the physical memory is under critical memory pressure.
+  if (phys_free <= critical_threshold_mb_)
+    return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
+
+  // Determine if the physical memory is under moderate memory pressure.
+  if (phys_free <= moderate_threshold_mb_)
+    return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
+
+  // No memory pressure was detected.
+  return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+}
+
+void DirectMemoryPressureCalculator::InferThresholds() {
+  // Determine if the memory installed is 'large' or 'small'. Default to 'large'
+  // on failure, which uses more conservative thresholds.
+  bool large_memory = true;
+  base::SystemMemoryInfoKB mem_info = {};
+  if (GetSystemMemoryInfo(&mem_info)) {
+    large_memory = mem_info.total / kKBperMB >=
+                   DirectMemoryPressureCalculator::kLargeMemoryThresholdMb;
+  }
+
+  if (large_memory) {
+    moderate_threshold_mb_ = kLargeMemoryDefaultModerateThresholdMb;
+    critical_threshold_mb_ = kLargeMemoryDefaultCriticalThresholdMb;
+  } else {
+    moderate_threshold_mb_ = kSmallMemoryDefaultModerateThresholdMb;
+    critical_threshold_mb_ = kSmallMemoryDefaultCriticalThresholdMb;
+  }
+}
+
+}  // namespace memory_pressure
diff --git a/components/memory_pressure/direct_memory_pressure_calculator_win_unittest.cc b/components/memory_pressure/direct_memory_pressure_calculator_win_unittest.cc
new file mode 100644
index 0000000..c4aa962
--- /dev/null
+++ b/components/memory_pressure/direct_memory_pressure_calculator_win_unittest.cc
@@ -0,0 +1,175 @@
+// Copyright 2015 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 "components/memory_pressure/direct_memory_pressure_calculator.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace memory_pressure {
+
+namespace {
+
+static const int kKBperMB = 1024;
+
+}  // namespace
+
+// This is out of the anonymous namespace space because it is a friend of
+// DirectMemoryPressureCalculator.
+class TestDirectMemoryPressureCalculator
+    : public DirectMemoryPressureCalculator {
+ public:
+  explicit TestDirectMemoryPressureCalculator(bool large_memory)
+      : DirectMemoryPressureCalculator(20, 10) {
+    // The values passed to the MemoryPressureCalculator constructor are dummy
+    // values that are immediately overwritten by InferTresholds.
+
+    // Generate a plausible amount of memory.
+    mem_info_.total = GenerateTotalMemoryMb(large_memory) * kKBperMB;
+
+    // Run InferThresholds using the test fixture's GetSystemMemoryStatus.
+    InferThresholds();
+  }
+
+  TestDirectMemoryPressureCalculator(int total_memory_mb,
+                                     int moderate_threshold_mb,
+                                     int critical_threshold_mb)
+      : DirectMemoryPressureCalculator(moderate_threshold_mb,
+                                       critical_threshold_mb) {
+    mem_info_.total = total_memory_mb * kKBperMB;
+  }
+
+  // Generates an amount of total memory that is consistent with the requested
+  // memory model.
+  static int GenerateTotalMemoryMb(bool large_memory) {
+    int total_mb = 64;
+    while (total_mb < kLargeMemoryThresholdMb)
+      total_mb *= 2;
+    if (large_memory)
+      return total_mb * 2;
+    return total_mb / 2;
+  }
+
+  // Sets up the memory status to reflect the provided absolute memory left.
+  void SetMemoryFree(int phys_left_mb) {
+    // |total| is set in the constructor and not modified.
+
+    // Set the amount of free memory.
+    mem_info_.free = phys_left_mb * kKBperMB;
+    DCHECK_LT(mem_info_.free, mem_info_.total);
+  }
+
+  void SetNone() { SetMemoryFree(moderate_threshold_mb() + 1); }
+
+  void SetModerate() { SetMemoryFree(moderate_threshold_mb() - 1); }
+
+  void SetCritical() { SetMemoryFree(critical_threshold_mb() - 1); }
+
+ private:
+  bool GetSystemMemoryInfo(base::SystemMemoryInfoKB* mem_info) const override {
+    // Simply copy the memory information set by the test fixture.
+    *mem_info = mem_info_;
+    return true;
+  }
+
+  base::SystemMemoryInfoKB mem_info_;
+};
+
+class DirectMemoryPressureCalculatorTest : public testing::Test {
+ public:
+  void CalculateCurrentPressureLevelTest(
+      TestDirectMemoryPressureCalculator* calc) {
+    int mod = calc->moderate_threshold_mb();
+    calc->SetMemoryFree(mod + 1);
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+              calc->CalculateCurrentPressureLevel());
+
+    calc->SetNone();
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+              calc->CalculateCurrentPressureLevel());
+
+    calc->SetMemoryFree(mod);
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+              calc->CalculateCurrentPressureLevel());
+
+    calc->SetMemoryFree(mod - 1);
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+              calc->CalculateCurrentPressureLevel());
+
+    int crit = calc->critical_threshold_mb();
+    calc->SetMemoryFree(crit + 1);
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+              calc->CalculateCurrentPressureLevel());
+
+    calc->SetModerate();
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+              calc->CalculateCurrentPressureLevel());
+
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+              calc->CalculateCurrentPressureLevel());
+
+    calc->SetMemoryFree(crit);
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+              calc->CalculateCurrentPressureLevel());
+
+    calc->SetMemoryFree(crit - 1);
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+              calc->CalculateCurrentPressureLevel());
+
+    calc->SetCritical();
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+              calc->CalculateCurrentPressureLevel());
+  }
+};
+
+// Tests the fundamental direct calculation of memory pressure with automatic
+// small-memory thresholds.
+TEST_F(DirectMemoryPressureCalculatorTest,
+       CalculateCurrentMemoryPressureLevelSmall) {
+  static const int kModerateMb =
+      DirectMemoryPressureCalculator::kSmallMemoryDefaultModerateThresholdMb;
+  static const int kCriticalMb =
+      DirectMemoryPressureCalculator::kSmallMemoryDefaultCriticalThresholdMb;
+
+  TestDirectMemoryPressureCalculator calc(false);  // Small-memory model.
+
+  EXPECT_EQ(kModerateMb, calc.moderate_threshold_mb());
+  EXPECT_EQ(kCriticalMb, calc.critical_threshold_mb());
+
+  ASSERT_NO_FATAL_FAILURE(CalculateCurrentPressureLevelTest(&calc));
+}
+
+// Tests the fundamental direct calculation of memory pressure with automatic
+// large-memory thresholds.
+TEST_F(DirectMemoryPressureCalculatorTest,
+       CalculateCurrentMemoryPressureLevelLarge) {
+  static const int kModerateMb =
+      DirectMemoryPressureCalculator::kLargeMemoryDefaultModerateThresholdMb;
+  static const int kCriticalMb =
+      DirectMemoryPressureCalculator::kLargeMemoryDefaultCriticalThresholdMb;
+
+  TestDirectMemoryPressureCalculator calc(true);  // Large-memory model.
+
+  EXPECT_EQ(kModerateMb, calc.moderate_threshold_mb());
+  EXPECT_EQ(kCriticalMb, calc.critical_threshold_mb());
+
+  ASSERT_NO_FATAL_FAILURE(CalculateCurrentPressureLevelTest(&calc));
+}
+
+// Tests the fundamental direct calculation of memory pressure with manually
+// specified threshold levels.
+TEST_F(DirectMemoryPressureCalculatorTest,
+       CalculateCurrentMemoryPressureLevelCustom) {
+  static const int kSystemMb = 512;
+  static const int kModerateMb = 256;
+  static const int kCriticalMb = 128;
+
+  TestDirectMemoryPressureCalculator calc(kSystemMb, kModerateMb, kCriticalMb);
+
+  EXPECT_EQ(kModerateMb, calc.moderate_threshold_mb());
+  EXPECT_EQ(kCriticalMb, calc.critical_threshold_mb());
+
+  ASSERT_NO_FATAL_FAILURE(CalculateCurrentPressureLevelTest(&calc));
+}
+
+}  // namespace memory_pressure
diff --git a/components/memory_pressure/filtered_memory_pressure_calculator.cc b/components/memory_pressure/filtered_memory_pressure_calculator.cc
new file mode 100644
index 0000000..9f5aa9d
--- /dev/null
+++ b/components/memory_pressure/filtered_memory_pressure_calculator.cc
@@ -0,0 +1,91 @@
+// Copyright 2015 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 "components/memory_pressure/filtered_memory_pressure_calculator.h"
+
+#include "base/time/default_tick_clock.h"
+
+namespace memory_pressure {
+
+#if defined(MEMORY_PRESSURE_IS_POLLING)
+
+// 100ms (10Hz) allows a relatively fast respsonse time for rapidly increasing
+// memory usage, but limits the amount of work done in the calculator.
+const int FilteredMemoryPressureCalculator::kMinimumTimeBetweenSamplesMs = 100;
+
+// These values were experimentally obtained during the initial ChromeOS only
+// implementation of this feature. By spending a significant cooldown period in
+// at a higher pressure level more time is dedicated to freeing resources and
+// less churn occurs in the MemoryPressureListener event stream.
+const int FilteredMemoryPressureCalculator::kCriticalPressureCooldownPeriodMs =
+    5000;
+const int FilteredMemoryPressureCalculator::kModeratePressureCooldownPeriodMs =
+    5000;
+
+FilteredMemoryPressureCalculator::FilteredMemoryPressureCalculator(
+    scoped_ptr<MemoryPressureCalculator> pressure_calculator)
+    : tick_clock_(new base::DefaultTickClock()),
+      pressure_calculator_(pressure_calculator.Pass()),
+      current_pressure_level_(
+          MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE),
+      samples_taken_(false),
+      cooldown_in_progress_(false) {}
+
+FilteredMemoryPressureCalculator::MemoryPressureLevel
+FilteredMemoryPressureCalculator::CalculateCurrentPressureLevel() {
+  base::TimeTicks now = tick_clock_->NowTicks();
+
+  // If its too soon to take a sample then return the precalculated value.
+  if (samples_taken_ &&
+      (now - last_sample_time_) <
+          base::TimeDelta::FromMilliseconds(kMinimumTimeBetweenSamplesMs)) {
+    return current_pressure_level_;
+  }
+
+  // Take a sample.
+  samples_taken_ = true;
+  last_sample_time_ = now;
+  MemoryPressureLevel level =
+      pressure_calculator_->CalculateCurrentPressureLevel();
+
+  // The pressure hasn't changed or has gone up. In either case this is the end
+  // of a cooldown period if one was in progress.
+  if (level >= current_pressure_level_) {
+    cooldown_in_progress_ = false;
+    current_pressure_level_ = level;
+    return level;
+  }
+
+  // The pressure has gone down, so apply cooldown hysteresis.
+  if (cooldown_in_progress_) {
+    cooldown_high_tide_ = std::max(cooldown_high_tide_, level);
+
+    // Get the cooldown period for the current level.
+    int cooldown_ms = kCriticalPressureCooldownPeriodMs;
+    if (current_pressure_level_ ==
+        MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE) {
+      cooldown_ms = kModeratePressureCooldownPeriodMs;
+    }
+    base::TimeDelta cooldown_period =
+        base::TimeDelta::FromMilliseconds(cooldown_ms);
+
+    if (now - cooldown_start_time_ >= cooldown_period) {
+      // The cooldown has completed successfully, so transition the pressure
+      // level.
+      cooldown_in_progress_ = false;
+      current_pressure_level_ = cooldown_high_tide_;
+    }
+  } else {
+    // Start a new cooldown period.
+    cooldown_in_progress_ = true;
+    cooldown_start_time_ = now;
+    cooldown_high_tide_ = level;
+  }
+
+  return current_pressure_level_;
+}
+
+#endif  // defined(MEMORY_PRESSURE_IS_POLLING)
+
+}  // namespace memory_pressure
diff --git a/components/memory_pressure/filtered_memory_pressure_calculator.h b/components/memory_pressure/filtered_memory_pressure_calculator.h
new file mode 100644
index 0000000..9d9b902
--- /dev/null
+++ b/components/memory_pressure/filtered_memory_pressure_calculator.h
@@ -0,0 +1,79 @@
+// Copyright 2015 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 COMPONENTS_MEMORY_PRESSURE_FILTERED_MEMORY_PRESSURE_CALCULATOR_H_
+#define COMPONENTS_MEMORY_PRESSURE_FILTERED_MEMORY_PRESSURE_CALCULATOR_H_
+
+#include "base/time/tick_clock.h"
+#include "components/memory_pressure/memory_pressure_calculator.h"
+
+namespace memory_pressure {
+
+#if defined(MEMORY_PRESSURE_IS_POLLING)
+
+// A utility class that provides rate-limiting and hysteresis on raw memory
+// pressure calculations. This is identical across all platforms, but only used
+// on those that do not have native memory pressure signals.
+class FilteredMemoryPressureCalculator : public MemoryPressureCalculator {
+ public:
+  // The minimum time that must pass between successive polls. This enforces an
+  // upper bound on the rate of calls to the contained MemoryPressureCalculator.
+  static const int kMinimumTimeBetweenSamplesMs;
+
+  // The cooldown period when transitioning from critical to moderate/no memory
+  // pressure, or from moderate to none.
+  static const int kCriticalPressureCooldownPeriodMs;
+  static const int kModeratePressureCooldownPeriodMs;
+
+  explicit FilteredMemoryPressureCalculator(
+      scoped_ptr<MemoryPressureCalculator> pressure_calculator);
+  ~FilteredMemoryPressureCalculator() {}
+
+  // Calculates the current pressure level.
+  MemoryPressureLevel CalculateCurrentPressureLevel() override;
+
+  // Testing seam for configuring the tick clock in use.
+  void set_tick_clock(scoped_ptr<base::TickClock> tick_clock) {
+    tick_clock_ = tick_clock.Pass();
+  }
+
+  // Accessors for unittesting.
+  bool cooldown_in_progress() const { return cooldown_in_progress_; }
+  base::TimeTicks cooldown_start_time() const { return cooldown_start_time_; }
+  MemoryPressureLevel cooldown_high_tide() const { return cooldown_high_tide_; }
+
+ private:
+  friend class TestFilteredMemoryPressureCalculator;
+
+  // The delegate tick clock. This is settable as a testing seam.
+  scoped_ptr<base::TickClock> tick_clock_;
+
+  // The delegate pressure calculator. Provided by the constructor.
+  scoped_ptr<MemoryPressureCalculator> pressure_calculator_;
+
+  // The memory pressure currently being reported.
+  MemoryPressureLevel current_pressure_level_;
+
+  // The last time a sample was taken.
+  bool samples_taken_;
+  base::TimeTicks last_sample_time_;
+
+  // State of an ongoing cooldown period, if any. The high-tide line indicates
+  // the highest memory pressure level (*below* the current one) that was
+  // encountered during the cooldown period. This allows a cooldown to
+  // transition directly from critical to none if *no* moderate pressure signals
+  // were seen during the period, otherwise it forces it to pass through a
+  // moderate cooldown as well.
+  bool cooldown_in_progress_;
+  base::TimeTicks cooldown_start_time_;
+  MemoryPressureLevel cooldown_high_tide_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilteredMemoryPressureCalculator);
+};
+
+#endif  // defined(MEMORY_PRESSURE_IS_POLLING)
+
+}  // namespace memory_pressure
+
+#endif  // COMPONENTS_MEMORY_PRESSURE_FILTERED_MEMORY_PRESSURE_CALCULATOR_H_
diff --git a/components/memory_pressure/filtered_memory_pressure_calculator_unittest.cc b/components/memory_pressure/filtered_memory_pressure_calculator_unittest.cc
new file mode 100644
index 0000000..81b7723
--- /dev/null
+++ b/components/memory_pressure/filtered_memory_pressure_calculator_unittest.cc
@@ -0,0 +1,298 @@
+// Copyright 2015 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 "components/memory_pressure/filtered_memory_pressure_calculator.h"
+
+#include "base/test/simple_test_tick_clock.h"
+#include "components/memory_pressure/test_memory_pressure_calculator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace memory_pressure {
+
+#if defined(MEMORY_PRESSURE_IS_POLLING)
+
+class FilteredMemoryPressureCalculatorTest : public testing::Test {
+ public:
+  FilteredMemoryPressureCalculatorTest()
+      : calculator_(nullptr), tick_clock_(nullptr) {}
+
+  void SetUp() override {
+    // Ownership of the calculator and tick clock are both passed to the filter.
+    calculator_ = new TestMemoryPressureCalculator();
+    tick_clock_ = new base::SimpleTestTickClock();
+    filter_.reset(new FilteredMemoryPressureCalculator(
+        scoped_ptr<MemoryPressureCalculator>(calculator_)));
+    filter_->set_tick_clock(scoped_ptr<base::TickClock>(tick_clock_));
+  }
+
+  void TearDown() override {
+    calculator_ = nullptr;
+    tick_clock_ = nullptr;
+    filter_.reset();
+  }
+
+  // Advances the tick clock by the given number of milliseconds.
+  void Tick(int ms) {
+    tick_clock_->Advance(base::TimeDelta::FromMilliseconds(ms));
+  }
+
+  // Delegates that are inject into the filter under test.
+  TestMemoryPressureCalculator* calculator_;
+  base::SimpleTestTickClock* tick_clock_;
+
+  // The object under test.
+  scoped_ptr<FilteredMemoryPressureCalculator> filter_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FilteredMemoryPressureCalculatorTest);
+};
+
+TEST_F(FilteredMemoryPressureCalculatorTest, FirstCallInvokesCalculator) {
+  calculator_->SetCritical();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(1, calculator_->calls());
+  EXPECT_FALSE(filter_->cooldown_in_progress());
+}
+
+TEST_F(FilteredMemoryPressureCalculatorTest, CalculatorNotAlwaysInvoked) {
+  calculator_->SetModerate();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(1, calculator_->calls());
+  EXPECT_FALSE(filter_->cooldown_in_progress());
+
+  // Change the pressure reported by the caculator, but don't expect the filter
+  // to report the critical value until a minimum sampling period has passed.
+  // The level has to be increasing so that hysteresis doesn't come into play.
+  calculator_->SetCritical();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(1, calculator_->calls());
+  EXPECT_FALSE(filter_->cooldown_in_progress());
+
+  Tick(FilteredMemoryPressureCalculator::kMinimumTimeBetweenSamplesMs / 2);
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(1, calculator_->calls());
+  EXPECT_FALSE(filter_->cooldown_in_progress());
+
+  // A sufficient time has passed so now it should report the new level.
+  Tick(FilteredMemoryPressureCalculator::kMinimumTimeBetweenSamplesMs);
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(2, calculator_->calls());
+  EXPECT_FALSE(filter_->cooldown_in_progress());
+}
+
+TEST_F(FilteredMemoryPressureCalculatorTest, CooldownCriticalToModerate) {
+  calculator_->SetCritical();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(1, calculator_->calls());
+  EXPECT_FALSE(filter_->cooldown_in_progress());
+
+  // Initiate a cooldown period by jumping sufficiently far ahead for another
+  // sample.
+  Tick(FilteredMemoryPressureCalculator::kMinimumTimeBetweenSamplesMs);
+  calculator_->SetModerate();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(2, calculator_->calls());
+  EXPECT_TRUE(filter_->cooldown_in_progress());
+  EXPECT_EQ(tick_clock_->NowTicks(), filter_->cooldown_start_time());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            filter_->cooldown_high_tide());
+
+  // Step another sample interval and it should still not have changed.
+  Tick(FilteredMemoryPressureCalculator::kMinimumTimeBetweenSamplesMs);
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(3, calculator_->calls());
+  EXPECT_TRUE(filter_->cooldown_in_progress());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            filter_->cooldown_high_tide());
+
+  // Step the cooldown period and it should change state.
+  Tick(FilteredMemoryPressureCalculator::kCriticalPressureCooldownPeriodMs);
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(4, calculator_->calls());
+  EXPECT_FALSE(filter_->cooldown_in_progress());
+}
+
+TEST_F(FilteredMemoryPressureCalculatorTest,
+       CooldownCriticalToModerateViaNone) {
+  calculator_->SetCritical();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(1, calculator_->calls());
+  EXPECT_FALSE(filter_->cooldown_in_progress());
+
+  // Initiate a cooldown period by jumping sufficiently far ahead for another
+  // sample. First go directly to no memory pressure before passing back through
+  // moderate. The final result should be a moderate memory pressure.
+  Tick(FilteredMemoryPressureCalculator::kMinimumTimeBetweenSamplesMs);
+  calculator_->SetNone();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(2, calculator_->calls());
+  EXPECT_TRUE(filter_->cooldown_in_progress());
+  EXPECT_EQ(tick_clock_->NowTicks(), filter_->cooldown_start_time());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            filter_->cooldown_high_tide());
+
+  // Step another sample interval and it should still not have changed.
+  Tick(FilteredMemoryPressureCalculator::kMinimumTimeBetweenSamplesMs);
+  calculator_->SetModerate();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(3, calculator_->calls());
+  EXPECT_TRUE(filter_->cooldown_in_progress());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            filter_->cooldown_high_tide());
+
+  // Step the cooldown period and it should change state.
+  Tick(FilteredMemoryPressureCalculator::kCriticalPressureCooldownPeriodMs);
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(4, calculator_->calls());
+  EXPECT_FALSE(filter_->cooldown_in_progress());
+}
+
+TEST_F(FilteredMemoryPressureCalculatorTest, CooldownCriticalToNone) {
+  calculator_->SetCritical();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(1, calculator_->calls());
+  EXPECT_FALSE(filter_->cooldown_in_progress());
+
+  // Initiate a cooldown period by jumping sufficiently far ahead for another
+  // sample.
+  Tick(FilteredMemoryPressureCalculator::kMinimumTimeBetweenSamplesMs);
+  calculator_->SetNone();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(2, calculator_->calls());
+  EXPECT_TRUE(filter_->cooldown_in_progress());
+  EXPECT_EQ(tick_clock_->NowTicks(), filter_->cooldown_start_time());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            filter_->cooldown_high_tide());
+
+  // Step another sample interval and it should still not have changed.
+  Tick(FilteredMemoryPressureCalculator::kMinimumTimeBetweenSamplesMs);
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(3, calculator_->calls());
+  EXPECT_TRUE(filter_->cooldown_in_progress());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            filter_->cooldown_high_tide());
+
+  // Step the cooldown period and it should change state.
+  Tick(FilteredMemoryPressureCalculator::kCriticalPressureCooldownPeriodMs);
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(4, calculator_->calls());
+  EXPECT_FALSE(filter_->cooldown_in_progress());
+}
+
+TEST_F(FilteredMemoryPressureCalculatorTest, CooldownModerateToNone) {
+  calculator_->SetModerate();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(1, calculator_->calls());
+  EXPECT_FALSE(filter_->cooldown_in_progress());
+
+  // Initiate a cooldown period by jumping sufficiently far ahead for another
+  // sample.
+  Tick(FilteredMemoryPressureCalculator::kMinimumTimeBetweenSamplesMs);
+  calculator_->SetNone();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(2, calculator_->calls());
+  EXPECT_TRUE(filter_->cooldown_in_progress());
+  EXPECT_EQ(tick_clock_->NowTicks(), filter_->cooldown_start_time());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            filter_->cooldown_high_tide());
+
+  // Step another sample interval and it should still not have changed.
+  Tick(FilteredMemoryPressureCalculator::kMinimumTimeBetweenSamplesMs);
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(3, calculator_->calls());
+  EXPECT_TRUE(filter_->cooldown_in_progress());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            filter_->cooldown_high_tide());
+
+  // Step the cooldown period and it should change state.
+  Tick(FilteredMemoryPressureCalculator::kModeratePressureCooldownPeriodMs);
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(4, calculator_->calls());
+  EXPECT_FALSE(filter_->cooldown_in_progress());
+}
+
+TEST_F(FilteredMemoryPressureCalculatorTest, InterruptedCooldownModerate) {
+  calculator_->SetModerate();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(1, calculator_->calls());
+  EXPECT_FALSE(filter_->cooldown_in_progress());
+
+  // Initiate a cooldown period by jumping sufficiently far ahead for another
+  // sample.
+  Tick(FilteredMemoryPressureCalculator::kMinimumTimeBetweenSamplesMs);
+  calculator_->SetNone();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(2, calculator_->calls());
+  EXPECT_TRUE(filter_->cooldown_in_progress());
+  EXPECT_EQ(tick_clock_->NowTicks(), filter_->cooldown_start_time());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            filter_->cooldown_high_tide());
+
+  // Step another sample interval and it should still not have changed. Since
+  // the pressure level has increased back to moderate it should also end the
+  // cooldown period.
+  Tick(FilteredMemoryPressureCalculator::kMinimumTimeBetweenSamplesMs);
+  calculator_->SetModerate();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(3, calculator_->calls());
+  EXPECT_FALSE(filter_->cooldown_in_progress());
+}
+
+TEST_F(FilteredMemoryPressureCalculatorTest, InterruptedCooldownCritical) {
+  calculator_->SetModerate();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(1, calculator_->calls());
+  EXPECT_FALSE(filter_->cooldown_in_progress());
+
+  // Initiate a cooldown period by jumping sufficiently far ahead for another
+  // sample.
+  Tick(FilteredMemoryPressureCalculator::kMinimumTimeBetweenSamplesMs);
+  calculator_->SetNone();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(2, calculator_->calls());
+  EXPECT_TRUE(filter_->cooldown_in_progress());
+  EXPECT_EQ(tick_clock_->NowTicks(), filter_->cooldown_start_time());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            filter_->cooldown_high_tide());
+
+  // Step another sample interval and it should still not have changed. Since
+  // the pressure level has increased to critical it ends the cooldown period
+  // and immediately reports the critical memory pressure.
+  Tick(FilteredMemoryPressureCalculator::kMinimumTimeBetweenSamplesMs);
+  calculator_->SetCritical();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            filter_->CalculateCurrentPressureLevel());
+  EXPECT_EQ(3, calculator_->calls());
+  EXPECT_FALSE(filter_->cooldown_in_progress());
+}
+
+#endif  // defined(MEMORY_PRESSURE_IS_POLLING)
+
+}  // namespace memory_pressure
diff --git a/components/memory_pressure/memory_pressure_calculator.h b/components/memory_pressure/memory_pressure_calculator.h
new file mode 100644
index 0000000..b139efe
--- /dev/null
+++ b/components/memory_pressure/memory_pressure_calculator.h
@@ -0,0 +1,32 @@
+// Copyright 2015 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 COMPONENTS_MEMORY_PRESSURE_MEMORY_PRESSURE_CALCULATOR_H_
+#define COMPONENTS_MEMORY_PRESSURE_MEMORY_PRESSURE_CALCULATOR_H_
+
+#include "components/memory_pressure/memory_pressure_listener.h"
+
+namespace memory_pressure {
+
+#if defined(MEMORY_PRESSURE_IS_POLLING)
+
+// Interface for a utility class that calculates memory pressure. Only used on
+// platforms without native memory pressure signals.
+class MemoryPressureCalculator {
+ public:
+  using MemoryPressureLevel = MemoryPressureListener::MemoryPressureLevel;
+
+  MemoryPressureCalculator() {}
+  virtual ~MemoryPressureCalculator() {}
+  virtual MemoryPressureLevel CalculateCurrentPressureLevel() = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MemoryPressureCalculator);
+};
+
+#endif  // defined(MEMORY_PRESSURE_IS_POLLING)
+
+}  // namespace memory_pressure
+
+#endif  // COMPONENTS_MEMORY_PRESSURE_MEMORY_PRESSURE_CALCULATOR_H_
diff --git a/components/memory_pressure/memory_pressure_listener.cc b/components/memory_pressure/memory_pressure_listener.cc
new file mode 100644
index 0000000..3d2fe1a9
--- /dev/null
+++ b/components/memory_pressure/memory_pressure_listener.cc
@@ -0,0 +1,61 @@
+// Copyright 2015 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 "components/memory_pressure/memory_pressure_listener.h"
+
+#include "base/lazy_instance.h"
+#include "base/observer_list_threadsafe.h"
+#include "base/trace_event/trace_event.h"
+
+namespace memory_pressure {
+
+namespace {
+
+// ObserverListThreadSafe is RefCountedThreadSafe, this traits is needed
+// to ensure the LazyInstance will hold a reference to it.
+struct LeakyLazyObserverListTraits
+    : base::internal::LeakyLazyInstanceTraits<
+          base::ObserverListThreadSafe<MemoryPressureListener>> {
+  static base::ObserverListThreadSafe<MemoryPressureListener>* New(
+      void* instance) {
+    base::ObserverListThreadSafe<MemoryPressureListener>* ret =
+        base::internal::LeakyLazyInstanceTraits<base::ObserverListThreadSafe<
+            MemoryPressureListener>>::New(instance);
+    // Leaky.
+    ret->AddRef();
+    return ret;
+  }
+};
+
+base::LazyInstance<base::ObserverListThreadSafe<MemoryPressureListener>,
+                   LeakyLazyObserverListTraits> g_observers =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+MemoryPressureListener::MemoryPressureListener(
+    const MemoryPressureListener::MemoryPressureCallback& callback)
+    : callback_(callback) {
+  g_observers.Get().AddObserver(this);
+}
+
+MemoryPressureListener::~MemoryPressureListener() {
+  g_observers.Get().RemoveObserver(this);
+}
+
+void MemoryPressureListener::Notify(MemoryPressureLevel memory_pressure_level) {
+  callback_.Run(memory_pressure_level);
+}
+
+// static
+void MemoryPressureListener::NotifyMemoryPressure(
+    MemoryPressureLevel memory_pressure_level) {
+  DCHECK_NE(memory_pressure_level, MEMORY_PRESSURE_LEVEL_NONE);
+  TRACE_EVENT1("memory", "MemoryPressureListener::NotifyMemoryPressure",
+               "level", memory_pressure_level);
+  g_observers.Get().Notify(FROM_HERE, &MemoryPressureListener::Notify,
+                           memory_pressure_level);
+}
+
+}  // namespace memory_pressure
diff --git a/components/memory_pressure/memory_pressure_listener.h b/components/memory_pressure/memory_pressure_listener.h
new file mode 100644
index 0000000..b99f8b2
--- /dev/null
+++ b/components/memory_pressure/memory_pressure_listener.h
@@ -0,0 +1,92 @@
+// Copyright 2015 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.
+
+// MemoryPressureListener provides static APIs for handling memory pressure on
+// platforms that have such signals (Android, ChromeOS, Mac and Windows). When
+// such signals are received the app will try to discard buffers that aren't
+// deemed essential (individual modules will implement their own policy).
+
+#ifndef COMPONENTS_MEMORY_PRESSURE_MEMORY_PRESSURE_LISTENER_H_
+#define COMPONENTS_MEMORY_PRESSURE_MEMORY_PRESSURE_LISTENER_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+
+// ChromeOS and Linux operating systems will be added to this as they are
+// implemented.
+#if defined(OS_WIN)
+#define MEMORY_PRESSURE_IS_POLLING
+#endif
+
+namespace memory_pressure {
+
+// To start listening, create a new instance, passing a callback to a
+// function that takes a MemoryPressureLevel parameter. To stop listening,
+// simply delete the listener object. The implementation guarantees
+// that the callback will always be called on the thread that created
+// the listener.
+//
+// Note that even on the same thread, the callback is not guaranteed to be
+// called synchronously within the system memory pressure broadcast.
+// Please see notes in MemoryPressureLevel enum below: some levels are
+// absolutely critical, and if not enough memory is returned to the system,
+// it'll potentially kill the app, and then later the app will have to be
+// cold-started.
+//
+// Example:
+//
+//   void OnMemoryPressure(MemoryPressureLevel memory_pressure_level) {
+//     ...
+//   }
+//
+//   // Start listening.
+//   MemoryPressureListener* my_listener =
+//       new MemoryPressureListener(base::Bind(&OnMemoryPressure));
+//
+//   ...
+//
+//   // Stop listening.
+//   delete my_listener;
+//
+class MemoryPressureListener {
+ public:
+  // A Java counterpart will be generated for this enum.
+  // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base
+  enum MemoryPressureLevel {
+    // No problems, there is enough memory to use. This event is not sent via
+    // callback, but the enum is used in other places to find out the current
+    // state of the system.
+    MEMORY_PRESSURE_LEVEL_NONE = -1,
+
+    // Modules are advised to free buffers that are cheap to re-allocate and not
+    // immediately needed.
+    MEMORY_PRESSURE_LEVEL_MODERATE = 0,
+
+    // At this level, modules are advised to free all possible memory.  The
+    // alternative is to be killed by the system, which means all memory will
+    // have to be re-created, plus the cost of a cold start.
+    MEMORY_PRESSURE_LEVEL_CRITICAL = 2,
+  };
+
+  typedef base::Callback<void(MemoryPressureLevel)> MemoryPressureCallback;
+
+  explicit MemoryPressureListener(
+      const MemoryPressureCallback& memory_pressure_callback);
+  ~MemoryPressureListener();
+
+  // Intended for use by the platform specific implementation.
+  static void NotifyMemoryPressure(MemoryPressureLevel memory_pressure_level);
+
+ private:
+  void Notify(MemoryPressureLevel memory_pressure_level);
+
+  MemoryPressureCallback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryPressureListener);
+};
+
+}  // namespace memory_pressure
+
+#endif  // COMPONENTS_MEMORY_PRESSURE_MEMORY_PRESSURE_LISTENER_H_
diff --git a/components/memory_pressure/test_memory_pressure_calculator.cc b/components/memory_pressure/test_memory_pressure_calculator.cc
new file mode 100644
index 0000000..2e0aa5b2
--- /dev/null
+++ b/components/memory_pressure/test_memory_pressure_calculator.cc
@@ -0,0 +1,38 @@
+// Copyright 2015 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 "components/memory_pressure/test_memory_pressure_calculator.h"
+
+namespace memory_pressure {
+
+#if defined(MEMORY_PRESSURE_IS_POLLING)
+
+TestMemoryPressureCalculator::TestMemoryPressureCalculator()
+    : level_(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE), calls_(0) {}
+
+TestMemoryPressureCalculator::MemoryPressureLevel
+TestMemoryPressureCalculator::CalculateCurrentPressureLevel() {
+  ++calls_;
+  return level_;
+}
+
+void TestMemoryPressureCalculator::SetNone() {
+  level_ = MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+}
+
+void TestMemoryPressureCalculator::SetModerate() {
+  level_ = MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
+}
+
+void TestMemoryPressureCalculator::SetCritical() {
+  level_ = MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
+}
+
+void TestMemoryPressureCalculator::ResetCalls() {
+  calls_ = 0;
+}
+
+#endif  // defined(MEMORY_PRESSURE_IS_POLLING)
+
+}  // namespace memory_pressure
diff --git a/components/memory_pressure/test_memory_pressure_calculator.h b/components/memory_pressure/test_memory_pressure_calculator.h
new file mode 100644
index 0000000..20ad6719
--- /dev/null
+++ b/components/memory_pressure/test_memory_pressure_calculator.h
@@ -0,0 +1,49 @@
+// Copyright 2015 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 COMPONENTS_MEMORY_PRESSURE_TEST_MEMORY_PRESSURE_CALCULATOR_H_
+#define COMPONENTS_MEMORY_PRESSURE_TEST_MEMORY_PRESSURE_CALCULATOR_H_
+
+#include "components/memory_pressure/memory_pressure_calculator.h"
+
+namespace memory_pressure {
+
+#if defined(MEMORY_PRESSURE_IS_POLLING)
+
+// A mock memory pressure calculator for unittesting.
+class TestMemoryPressureCalculator : public MemoryPressureCalculator {
+ public:
+  TestMemoryPressureCalculator();
+  virtual ~TestMemoryPressureCalculator() {}
+
+  // MemoryPressureCalculator implementation.
+  MemoryPressureLevel CalculateCurrentPressureLevel() override;
+
+  // Sets the mock calculator to return no pressure.
+  void SetNone();
+
+  // Sets the mock calculator to return moderate pressure.
+  void SetModerate();
+
+  // Sets the mock calculator to return critical pressure.
+  void SetCritical();
+
+  // Resets the call counter to 'CalculateCurrentPressureLevel'.
+  void ResetCalls();
+
+  // Returns the number of calls to 'CalculateCurrentPressureLevel'.
+  int calls() const { return calls_; }
+
+ private:
+  MemoryPressureLevel level_;
+  int calls_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureCalculator);
+};
+
+#endif  // defined(MEMORY_PRESSURE_IS_POLLING)
+
+}  // namespace memory_pressure
+
+#endif  // COMPONENTS_MEMORY_PRESSURE_TEST_MEMORY_PRESSURE_CALCULATOR_H_