Update to Chromium //base at Chromium commit 82baa9afc6620c68cb2168f20bb65e77e3e57f0a.

This gets us to sometime during September 14, 2015.

TBR=jamesr@chromium.org

Review URL: https://codereview.chromium.org/2045223003 .
diff --git a/BUILD.gn b/BUILD.gn
index 86db541..fae5384 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -64,8 +64,6 @@
   sources = [
     "allocator/allocator_extension.cc",
     "allocator/allocator_extension.h",
-    "allocator/type_profiler_control.cc",
-    "allocator/type_profiler_control.h",
     "android/animation_frame_time_histogram.cc",
     "android/animation_frame_time_histogram.h",
     "android/apk_assets.cc",
@@ -649,13 +647,15 @@
 
   if (is_ios) {
     sources -= [
+      "files/file_path_watcher.cc",
+      "files/file_path_watcher.h",
+      "files/file_path_watcher_fsevents.cc",
+      "files/file_path_watcher_fsevents.h",
+      "files/file_path_watcher_kqueue.cc",
+      "files/file_path_watcher_kqueue.h",
       "message_loop/message_pump_libevent.cc",
       "message_loop/message_pump_libevent.h",
     ]
-
-    set_sources_assignment_filter([])
-    sources += [ "files/file_path_watcher_mac.cc" ]
-    set_sources_assignment_filter(sources_assignment_filter)
   }
 
   sources -= [
@@ -729,8 +729,6 @@
     set_sources_assignment_filter(sources_assignment_filter)
 
     sources -= [
-      "allocator/type_profiler_control.cc",
-      "allocator/type_profiler_control.h",
       "async_socket_io_handler_posix.cc",
       "cpu.cc",
       "files/file_enumerator_posix.cc",
@@ -1434,6 +1432,7 @@
     "win/registry_unittest.cc",
     "win/scoped_bstr_unittest.cc",
     "win/scoped_comptr_unittest.cc",
+    "win/scoped_handle_unittest.cc",
     "win/scoped_process_information_unittest.cc",
     "win/scoped_variant_unittest.cc",
     "win/shortcut_unittest.cc",
@@ -1481,6 +1480,7 @@
 
   if (is_ios) {
     sources -= [
+      "files/file_path_watcher_unittest.cc",
       "memory/discardable_shared_memory_unittest.cc",
       "memory/shared_memory_unittest.cc",
       "process/memory_unittest.cc",
diff --git a/allocator/BUILD.gn b/allocator/BUILD.gn
index b6b7fc2..c12431b 100644
--- a/allocator/BUILD.gn
+++ b/allocator/BUILD.gn
@@ -100,7 +100,7 @@
     check_includes = false
 
     sources = [
-      # Generated for our configuration from tcmalloc"s build
+      # Generated for our configuration from tcmalloc's build
       # and checked in.
       "$tcmalloc_dir/src/config.h",
       "$tcmalloc_dir/src/config_android.h",
@@ -151,8 +151,6 @@
 
       # #included by debugallocation_shim.cc
       #"$tcmalloc_dir/src/debugallocation.cc",
-      "$tcmalloc_dir/src/deep-heap-profile.cc",
-      "$tcmalloc_dir/src/deep-heap-profile.h",
       "$tcmalloc_dir/src/free_list.cc",
       "$tcmalloc_dir/src/free_list.h",
       "$tcmalloc_dir/src/heap-profile-table.cc",
diff --git a/allocator/type_profiler.cc b/allocator/type_profiler.cc
deleted file mode 100644
index 635fbcf..0000000
--- a/allocator/type_profiler.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#if defined(TYPE_PROFILING)
-
-#include "base/allocator/type_profiler.h"
-
-#include <assert.h>
-
-namespace {
-
-void* NopIntercept(void* ptr, size_t size, const std::type_info& type) {
-  return ptr;
-}
-
-base::type_profiler::InterceptFunction* g_new_intercept = NopIntercept;
-base::type_profiler::InterceptFunction* g_delete_intercept = NopIntercept;
-
-}
-
-void* __op_new_intercept__(void* ptr,
-                           size_t size,
-                           const std::type_info& type) {
-  return g_new_intercept(ptr, size, type);
-}
-
-void* __op_delete_intercept__(void* ptr,
-                              size_t size,
-                              const std::type_info& type) {
-  return g_delete_intercept(ptr, size, type);
-}
-
-namespace base {
-namespace type_profiler {
-
-// static
-void InterceptFunctions::SetFunctions(InterceptFunction* new_intercept,
-                                      InterceptFunction* delete_intercept) {
-  // Don't use DCHECK, as this file is injected into targets
-  // that do not and should not depend on base/base.gyp:base
-  assert(g_new_intercept == NopIntercept);
-  assert(g_delete_intercept == NopIntercept);
-
-  g_new_intercept = new_intercept;
-  g_delete_intercept = delete_intercept;
-}
-
-// static
-void InterceptFunctions::ResetFunctions() {
-  g_new_intercept = NopIntercept;
-  g_delete_intercept = NopIntercept;
-}
-
-// static
-bool InterceptFunctions::IsAvailable() {
-  return g_new_intercept != NopIntercept || g_delete_intercept != NopIntercept;
-}
-
-}  // namespace type_profiler
-}  // namespace base
-
-#endif  // defined(TYPE_PROFILING)
diff --git a/allocator/type_profiler.h b/allocator/type_profiler.h
deleted file mode 100644
index 86b5711..0000000
--- a/allocator/type_profiler.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_ALLOCATOR_TYPE_PROFILER_H_
-#define BASE_ALLOCATOR_TYPE_PROFILER_H_
-
-#if defined(TYPE_PROFILING)
-
-#include <stddef.h>  // for size_t
-#include <typeinfo>  // for std::typeinfo
-
-namespace base {
-namespace type_profiler {
-
-typedef void* InterceptFunction(void*, size_t, const std::type_info&);
-
-class InterceptFunctions {
- public:
-  // It must be called only once in a process while it is in single-thread.
-  // For now, ContentMainRunnerImpl::Initialize is the only supposed caller
-  // of this function except for single-threaded unit tests.
-  static void SetFunctions(InterceptFunction* new_intercept,
-                           InterceptFunction* delete_intercept);
-
- private:
-  friend class TypeProfilerTest;
-
-  // These functions are not thread safe.
-  // They must be used only from single-threaded unit tests.
-  static void ResetFunctions();
-  static bool IsAvailable();
-};
-
-}  // namespace type_profiler
-}  // namespace base
-
-#endif  // defined(TYPE_PROFILING)
-
-#endif  // BASE_ALLOCATOR_TYPE_PROFILER_H_
diff --git a/allocator/type_profiler_control.cc b/allocator/type_profiler_control.cc
deleted file mode 100644
index 6be7984..0000000
--- a/allocator/type_profiler_control.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/allocator/type_profiler_control.h"
-
-namespace base {
-namespace type_profiler {
-
-namespace {
-
-#if defined(TYPE_PROFILING)
-const bool kTypeProfilingEnabled = true;
-#else
-const bool kTypeProfilingEnabled = false;
-#endif
-
-bool g_enable_intercept = kTypeProfilingEnabled;
-
-}  // namespace
-
-// static
-void Controller::Stop() {
-  g_enable_intercept = false;
-}
-
-// static
-bool Controller::IsProfiling() {
-  return kTypeProfilingEnabled && g_enable_intercept;
-}
-
-// static
-void Controller::Restart() {
-  g_enable_intercept = kTypeProfilingEnabled;
-}
-
-}  // namespace type_profiler
-}  // namespace base
diff --git a/allocator/type_profiler_control.h b/allocator/type_profiler_control.h
deleted file mode 100644
index 17cf5b6..0000000
--- a/allocator/type_profiler_control.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_
-#define BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_
-
-#include "base/gtest_prod_util.h"
-
-namespace base {
-namespace type_profiler {
-
-class Controller {
- public:
-  static void Stop();
-  static bool IsProfiling();
-
- private:
-  FRIEND_TEST_ALL_PREFIXES(TypeProfilerTest,
-                           TestProfileNewWithoutProfiledDelete);
-
-  // It must be used only from allowed unit tests.  The following is only
-  // allowed for use in unit tests. Profiling should never be restarted in
-  // regular use.
-  static void Restart();
-};
-
-}  // namespace type_profiler
-}  // namespace base
-
-#endif  // BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_
diff --git a/allocator/type_profiler_map_unittest.cc b/allocator/type_profiler_map_unittest.cc
deleted file mode 100644
index 514ec16..0000000
--- a/allocator/type_profiler_map_unittest.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This is a unittest set for type_profiler_map in third_party/tcmalloc.  It is
-// independent from other tests and executed manually like allocator_unittests
-// since type_profiler_map is a singleton (like TCMalloc's heap-profiler), and
-// it requires RTTI and different compiling/linking options from others.
-
-#if defined(TYPE_PROFILING)
-
-#include "base/memory/scoped_ptr.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/tcmalloc/chromium/src/gperftools/type_profiler_map.h"
-
-namespace base {
-namespace type_profiler {
-
-static const void* const g_const_null = static_cast<const void*>(NULL);
-
-TEST(TypeProfilerMapTest, NormalOperation) {
-  // Allocate an object just to get a valid address.
-  // This 'new' is not profiled by type_profiler.
-  scoped_ptr<int> dummy(new int(48));
-  const std::type_info* type;
-
-  type = LookupType(dummy.get());
-  EXPECT_EQ(g_const_null, type);
-
-  InsertType(dummy.get(), 12, typeid(int));
-  type = LookupType(dummy.get());
-  ASSERT_NE(g_const_null, type);
-  EXPECT_STREQ(typeid(int).name(), type->name());
-
-  EraseType(dummy.get());
-  type = LookupType(dummy.get());
-  EXPECT_EQ(g_const_null, type);
-}
-
-TEST(TypeProfilerMapTest, EraseWithoutInsert) {
-  scoped_ptr<int> dummy(new int(48));
-  const std::type_info* type;
-
-  for (int i = 0; i < 10; ++i) {
-    EraseType(dummy.get());
-    type = LookupType(dummy.get());
-    EXPECT_EQ(g_const_null, type);
-  }
-}
-
-TEST(TypeProfilerMapTest, InsertThenMultipleErase) {
-  scoped_ptr<int> dummy(new int(48));
-  const std::type_info* type;
-
-  InsertType(dummy.get(), 12, typeid(int));
-  type = LookupType(dummy.get());
-  ASSERT_NE(g_const_null, type);
-  EXPECT_STREQ(typeid(int).name(), type->name());
-
-  for (int i = 0; i < 10; ++i) {
-    EraseType(dummy.get());
-    type = LookupType(dummy.get());
-    EXPECT_EQ(g_const_null, type);
-  }
-}
-
-TEST(TypeProfilerMapTest, MultipleInsertWithoutErase) {
-  scoped_ptr<int> dummy(new int(48));
-  const std::type_info* type;
-
-  InsertType(dummy.get(), 12, typeid(int));
-  type = LookupType(dummy.get());
-  ASSERT_NE(g_const_null, type);
-  EXPECT_STREQ(typeid(int).name(), type->name());
-
-  InsertType(dummy.get(), 5, typeid(char));
-  type = LookupType(dummy.get());
-  ASSERT_NE(g_const_null, type);
-  EXPECT_STREQ(typeid(char).name(), type->name());
-
-  InsertType(dummy.get(), 129, typeid(long));
-  type = LookupType(dummy.get());
-  ASSERT_NE(g_const_null, type);
-  EXPECT_STREQ(typeid(long).name(), type->name());
-
-  EraseType(dummy.get());
-  type = LookupType(dummy.get());
-  EXPECT_EQ(g_const_null, type);
-}
-
-}  // namespace type_profiler
-}  // namespace base
-
-#endif  // defined(TYPE_PROFILING)
-
-int main(int argc, char** argv) {
-  testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
-}
diff --git a/allocator/type_profiler_tcmalloc.cc b/allocator/type_profiler_tcmalloc.cc
deleted file mode 100644
index e5e10e0..0000000
--- a/allocator/type_profiler_tcmalloc.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#if defined(TYPE_PROFILING)
-
-#include "base/allocator/type_profiler_tcmalloc.h"
-
-#include "base/allocator/type_profiler_control.h"
-#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
-#include "third_party/tcmalloc/chromium/src/gperftools/type_profiler_map.h"
-
-namespace base {
-namespace type_profiler {
-
-void* NewInterceptForTCMalloc(void* ptr,
-                              size_t size,
-                              const std::type_info& type) {
-  if (Controller::IsProfiling())
-    InsertType(ptr, size, type);
-
-  return ptr;
-}
-
-void* DeleteInterceptForTCMalloc(void* ptr,
-                                 size_t size,
-                                 const std::type_info& type) {
-  if (Controller::IsProfiling())
-    EraseType(ptr);
-
-  return ptr;
-}
-
-}  // namespace type_profiler
-}  // namespace base
-
-#endif  // defined(TYPE_PROFILING)
diff --git a/allocator/type_profiler_tcmalloc.h b/allocator/type_profiler_tcmalloc.h
deleted file mode 100644
index ac55995..0000000
--- a/allocator/type_profiler_tcmalloc.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_ALLOCATOR_TYPE_PROFILER_TCMALLOC_H_
-#define BASE_ALLOCATOR_TYPE_PROFILER_TCMALLOC_H_
-
-#if defined(TYPE_PROFILING)
-
-#include <cstddef>  // for size_t
-#include <typeinfo>  // for std::type_info
-
-namespace base {
-namespace type_profiler {
-
-void* NewInterceptForTCMalloc(void* ptr,
-                              size_t size,
-                              const std::type_info& type);
-
-void* DeleteInterceptForTCMalloc(void* ptr,
-                                 size_t size,
-                                 const std::type_info& type);
-
-}  // namespace type_profiler
-}  // namespace base
-
-#endif  // defined(TYPE_PROFILING)
-
-#endif  // BASE_ALLOCATOR_TYPE_PROFILER_TCMALLOC_H_
diff --git a/allocator/type_profiler_unittest.cc b/allocator/type_profiler_unittest.cc
deleted file mode 100644
index 3d7369c38..0000000
--- a/allocator/type_profiler_unittest.cc
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This is a unittest set for type_profiler.  It is independent from other
-// tests and executed manually like allocator_unittests since type_profiler_map
-// used in type_profiler is a singleton (like TCMalloc's heap-profiler), and
-// it requires RTTI and different compiling/linking options from others
-//
-// It tests that the profiler doesn't fail in suspicous cases.  For example,
-// 'new' is not profiled, but 'delete' for the created object is profiled.
-
-#if defined(TYPE_PROFILING)
-
-#include "base/allocator/type_profiler.h"
-#include "base/allocator/type_profiler_control.h"
-#include "base/allocator/type_profiler_tcmalloc.h"
-#include "base/basictypes.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/tcmalloc/chromium/src/gperftools/type_profiler_map.h"
-
-namespace base {
-namespace type_profiler {
-
-class TypeProfilerTest : public testing::Test {
- public:
-  TypeProfilerTest() {}
-
-  void SetInterceptFunctions() {
-    InterceptFunctions::SetFunctions(NewInterceptForTCMalloc,
-                                     DeleteInterceptForTCMalloc);
-  }
-
-  void ResetInterceptFunctions() {
-    InterceptFunctions::ResetFunctions();
-  }
-
-  void SetUp() {
-    SetInterceptFunctions();
-  }
-
-  void TearDown() {
-    ResetInterceptFunctions();
-  }
-
- protected:
-  static const size_t kDummyArraySize;
-  static const void* const kConstNull;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TypeProfilerTest);
-};
-
-const size_t TypeProfilerTest::kDummyArraySize = 10;
-const void* const TypeProfilerTest::kConstNull = static_cast<const void*>(NULL);
-
-TEST_F(TypeProfilerTest, TestNormalProfiling) {
-  int* dummy = new int(48);
-  const std::type_info* type;
-
-  type = LookupType(dummy);
-  ASSERT_NE(kConstNull, type);
-  EXPECT_STREQ(typeid(int).name(), type->name());
-  delete dummy;
-
-  type = LookupType(dummy);
-  EXPECT_EQ(kConstNull, type);
-}
-
-TEST_F(TypeProfilerTest, TestNormalArrayProfiling) {
-  int* dummy = new int[kDummyArraySize];
-  const std::type_info* type;
-
-  type = LookupType(dummy);
-  ASSERT_NE(kConstNull, type);
-  // For an array, the profiler remembers its base type.
-  EXPECT_STREQ(typeid(int).name(), type->name());
-  delete[] dummy;
-
-  type = LookupType(dummy);
-  EXPECT_EQ(kConstNull, type);
-}
-
-TEST_F(TypeProfilerTest, TestRepeatedNewAndDelete) {
-  int *dummy[kDummyArraySize];
-  const std::type_info* type;
-  for (int i = 0; i < kDummyArraySize; ++i)
-    dummy[i] = new int(i);
-
-  for (int i = 0; i < kDummyArraySize; ++i) {
-    type = LookupType(dummy[i]);
-    ASSERT_NE(kConstNull, type);
-    EXPECT_STREQ(typeid(int).name(), type->name());
-  }
-
-  for (int i = 0; i < kDummyArraySize; ++i) {
-    delete dummy[i];
-    type = LookupType(dummy[i]);
-    ASSERT_EQ(kConstNull, type);
-  }
-}
-
-TEST_F(TypeProfilerTest, TestMultipleNewWithDroppingDelete) {
-  static const size_t large_size = 256 * 1024;
-
-  char* dummy_char = new char[large_size / sizeof(*dummy_char)];
-  const std::type_info* type;
-
-  type = LookupType(dummy_char);
-  ASSERT_NE(kConstNull, type);
-  EXPECT_STREQ(typeid(char).name(), type->name());
-
-  // Call "::operator delete" directly to drop __op_delete_intercept__.
-  ::operator delete[](dummy_char);
-
-  type = LookupType(dummy_char);
-  ASSERT_NE(kConstNull, type);
-  EXPECT_STREQ(typeid(char).name(), type->name());
-
-  // Allocates a little different size.
-  int* dummy_int = new int[large_size / sizeof(*dummy_int) - 1];
-
-  // We expect that tcmalloc returns the same address for these large (over 32k)
-  // allocation calls.  It usually happens, but maybe probablistic.
-  ASSERT_EQ(static_cast<void*>(dummy_char), static_cast<void*>(dummy_int)) <<
-      "two new (malloc) calls didn't return the same address; retry it.";
-
-  type = LookupType(dummy_int);
-  ASSERT_NE(kConstNull, type);
-  EXPECT_STREQ(typeid(int).name(), type->name());
-
-  delete[] dummy_int;
-
-  type = LookupType(dummy_int);
-  EXPECT_EQ(kConstNull, type);
-}
-
-TEST_F(TypeProfilerTest, TestProfileDeleteWithoutProfiledNew) {
-  // 'dummy' should be new'ed in this test before intercept functions are set.
-  ResetInterceptFunctions();
-
-  int* dummy = new int(48);
-  const std::type_info* type;
-
-  // Set intercept functions again after 'dummy' is new'ed.
-  SetInterceptFunctions();
-
-  delete dummy;
-
-  type = LookupType(dummy);
-  EXPECT_EQ(kConstNull, type);
-
-  ResetInterceptFunctions();
-}
-
-TEST_F(TypeProfilerTest, TestProfileNewWithoutProfiledDelete) {
-  int* dummy = new int(48);
-  const std::type_info* type;
-
-  EXPECT_TRUE(Controller::IsProfiling());
-
-  // Stop profiling before deleting 'dummy'.
-  Controller::Stop();
-  EXPECT_FALSE(Controller::IsProfiling());
-
-  delete dummy;
-
-  // NOTE: We accept that a profile entry remains when a profiled object is
-  // deleted after Controller::Stop().
-  type = LookupType(dummy);
-  ASSERT_NE(kConstNull, type);
-  EXPECT_STREQ(typeid(int).name(), type->name());
-
-  Controller::Restart();
-  EXPECT_TRUE(Controller::IsProfiling());
-
-  // Remove manually since 'dummy' is not removed from type_profiler_map.
-  EraseType(dummy);
-}
-
-}  // namespace type_profiler
-}  // namespace base
-
-#endif  // defined(TYPE_PROFILING)
-
-int main(int argc, char** argv) {
-  testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
-}
diff --git a/android/java/src/org/chromium/base/PathUtils.java b/android/java/src/org/chromium/base/PathUtils.java
index 6f29732..c80124f 100644
--- a/android/java/src/org/chromium/base/PathUtils.java
+++ b/android/java/src/org/chromium/base/PathUtils.java
@@ -8,6 +8,7 @@
 import android.content.pm.ApplicationInfo;
 import android.os.AsyncTask;
 import android.os.Environment;
+import android.os.StrictMode;
 
 import org.chromium.base.annotations.CalledByNative;
 
@@ -115,8 +116,14 @@
     @SuppressWarnings("unused")
     @CalledByNative
     private static String getDownloadsDirectory(Context appContext) {
-        return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
-                .getPath();
+        // Temporarily allowing disk access while fixing. TODO: http://crbug.com/508615
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+        try {
+            return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
+                    .getPath();
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
     }
 
     /**
diff --git a/android/scoped_java_ref.h b/android/scoped_java_ref.h
index 6274969..94f94f5 100644
--- a/android/scoped_java_ref.h
+++ b/android/scoped_java_ref.h
@@ -193,6 +193,13 @@
   // This class is only good for use on the thread it was created on so
   // it's safe to cache the non-threadsafe JNIEnv* inside this object.
   JNIEnv* env_;
+
+  // Prevent ScopedJavaLocalRef(JNIEnv*, T obj) from being used to take
+  // ownership of a JavaParamRef's underlying object - parameters are not
+  // allowed to be deleted and so should not be owned by ScopedJavaLocalRef.
+  // TODO(torne): this can be removed once JavaParamRef no longer has an
+  // implicit conversion back to T.
+  ScopedJavaLocalRef(JNIEnv* env, const JavaParamRef<T>& other);
 };
 
 // Holds a global reference to a Java object. The global reference is scoped
diff --git a/basictypes.h b/basictypes.h
index d71abd9..e167466 100644
--- a/basictypes.h
+++ b/basictypes.h
@@ -28,7 +28,8 @@
 typedef int64_t int64;
 typedef uint64_t uint64;
 
-// DEPRECATED: Please use std::numeric_limits (from <limits>) instead.
+// DEPRECATED: Please use std::numeric_limits (from <limits>) or
+// (U)INT{8,16,32,64}_{MIN,MAX} in case of globals (and include <stdint.h>).
 const uint8  kuint8max  =  0xFF;
 const uint16 kuint16max =  0xFFFF;
 const uint32 kuint32max =  0xFFFFFFFF;
diff --git a/containers/scoped_ptr_map.h b/containers/scoped_ptr_map.h
index a4605e3..622a39d 100644
--- a/containers/scoped_ptr_map.h
+++ b/containers/scoped_ptr_map.h
@@ -42,9 +42,9 @@
 
   ScopedPtrMap() {}
   ~ScopedPtrMap() { clear(); }
-  ScopedPtrMap(ScopedPtrMap<Key, ScopedPtr>&& other) { swap(other); }
+  ScopedPtrMap(ScopedPtrMap&& other) { swap(other); }
 
-  ScopedPtrMap& operator=(ScopedPtrMap<Key, ScopedPtr>&& rhs) {
+  ScopedPtrMap& operator=(ScopedPtrMap&& rhs) {
     swap(rhs);
     return *this;
   }
@@ -61,7 +61,7 @@
   const_iterator begin() const { return data_.begin(); }
   const_iterator end() const { return data_.end(); }
 
-  void swap(ScopedPtrMap<Key, ScopedPtr>& other) { data_.swap(other.data_); }
+  void swap(ScopedPtrMap& other) { data_.swap(other.data_); }
 
   void clear() { STLDeleteValues(&data_); }
 
diff --git a/containers/scoped_ptr_map_unittest.cc b/containers/scoped_ptr_map_unittest.cc
index 46843b3..706b2ed 100644
--- a/containers/scoped_ptr_map_unittest.cc
+++ b/containers/scoped_ptr_map_unittest.cc
@@ -147,15 +147,30 @@
 
 TEST(ScopedPtrMapTest, Compare) {
   // Construct a ScopedPtrMap with a custom comparison function.
-  bool destroyed = false;
-  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>, std::greater<int>> scoped_map;
-  scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
-  scoped_map.insert(1, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
+  ScopedPtrMap<int, scoped_ptr<int>, std::greater<int>> scoped_map1;
+  scoped_map1.insert(0, make_scoped_ptr(new int(0)));
+  scoped_map1.insert(1, make_scoped_ptr(new int(0)));
 
-  auto it = scoped_map.begin();
+  auto it = scoped_map1.begin();
   EXPECT_EQ(1, it->first);
   ++it;
   EXPECT_EQ(0, it->first);
+
+  // Test the move constructor.
+  ScopedPtrMap<int, scoped_ptr<int>, std::greater<int>> scoped_map2(
+      scoped_map1.Pass());
+  EXPECT_EQ(2u, scoped_map2.size());
+  EXPECT_TRUE(scoped_map1.empty());
+
+  // Test move assignment.
+  scoped_map1 = scoped_map2.Pass();
+  EXPECT_EQ(2u, scoped_map1.size());
+  EXPECT_TRUE(scoped_map2.empty());
+
+  // Test swap.
+  scoped_map2.swap(scoped_map1);
+  EXPECT_EQ(2u, scoped_map2.size());
+  EXPECT_TRUE(scoped_map1.empty());
 }
 
 TEST(ScopedPtrMapTest, Scope) {
diff --git a/linux_util.cc b/linux_util.cc
index d6cd504..d94588f 100644
--- a/linux_util.cc
+++ b/linux_util.cc
@@ -37,7 +37,7 @@
  public:
   // Retrieves the Singleton.
   static LinuxDistroHelper* GetInstance() {
-    return Singleton<LinuxDistroHelper>::get();
+    return base::Singleton<LinuxDistroHelper>::get();
   }
 
   // The simple state machine goes from:
@@ -106,7 +106,7 @@
   argv.push_back("lsb_release");
   argv.push_back("-d");
   std::string output;
-  base::GetAppOutput(CommandLine(argv), &output);
+  GetAppOutput(CommandLine(argv), &output);
   if (output.length() > 0) {
     // lsb_release -d should return: Description:<tab>Distro Info
     const char field[] = "Description:\t";
@@ -124,8 +124,8 @@
 
 void SetLinuxDistro(const std::string& distro) {
   std::string trimmed_distro;
-  base::TrimWhitespaceASCII(distro, base::TRIM_ALL, &trimmed_distro);
-  base::strlcpy(g_linux_distro, trimmed_distro.c_str(), kDistroSize);
+  TrimWhitespaceASCII(distro, TRIM_ALL, &trimmed_distro);
+  strlcpy(g_linux_distro, trimmed_distro.c_str(), kDistroSize);
 }
 
 pid_t FindThreadIDWithSyscall(pid_t pid, const std::string& expected_data,
diff --git a/logging_win.cc b/logging_win.cc
index 53cc37c..319ae8a 100644
--- a/logging_win.cc
+++ b/logging_win.cc
@@ -18,8 +18,8 @@
 }
 
 LogEventProvider* LogEventProvider::GetInstance() {
-  return Singleton<LogEventProvider,
-                   StaticMemorySingletonTraits<LogEventProvider> >::get();
+  return base::Singleton<LogEventProvider, base::StaticMemorySingletonTraits<
+                                               LogEventProvider>>::get();
 }
 
 bool LogEventProvider::LogMessage(logging::LogSeverity severity,
diff --git a/logging_win.h b/logging_win.h
index aa48e22..de34a64 100644
--- a/logging_win.h
+++ b/logging_win.h
@@ -12,8 +12,10 @@
 #include "base/win/event_trace_provider.h"
 #include "base/logging.h"
 
+namespace base {
 template <typename Type>
 struct StaticMemorySingletonTraits;
+}  // namespace base
 
 namespace logging {
 
@@ -71,7 +73,7 @@
   // restored in OnEventsDisabled.
   logging::LogSeverity old_log_level_;
 
-  friend struct StaticMemorySingletonTraits<LogEventProvider>;
+  friend struct base::StaticMemorySingletonTraits<LogEventProvider>;
   DISALLOW_COPY_AND_ASSIGN(LogEventProvider);
 };
 
diff --git a/memory/singleton.h b/memory/singleton.h
index e50bdc0..7319699 100644
--- a/memory/singleton.h
+++ b/memory/singleton.h
@@ -36,10 +36,10 @@
 // we can implement the more complicated pieces out of line in the .cc file.
 BASE_EXPORT subtle::AtomicWord WaitForInstance(subtle::AtomicWord* instance);
 
-}  // namespace internal
-}  // namespace base
+class DeleteTraceLogForTesting;
 
-// TODO(joth): Move more of this file into namespace base
+}  // namespace internal
+
 
 // Default traits for Singleton<Type>. Calls operator new and operator delete on
 // the object. Registers automatic deletion at process exit.
@@ -110,7 +110,7 @@
   // this is traits for returning NULL.
   static Type* New() {
     // Only constructs once and returns pointer; otherwise returns NULL.
-    if (base::subtle::NoBarrier_AtomicExchange(&dead_, 1))
+    if (subtle::NoBarrier_AtomicExchange(&dead_, 1))
       return NULL;
 
     return new(buffer_.void_data()) Type();
@@ -125,20 +125,19 @@
   static const bool kAllowedToAccessOnNonjoinableThread = true;
 
   // Exposed for unittesting.
-  static void Resurrect() {
-    base::subtle::NoBarrier_Store(&dead_, 0);
-  }
+  static void Resurrect() { subtle::NoBarrier_Store(&dead_, 0); }
 
  private:
-  static base::AlignedMemory<sizeof(Type), ALIGNOF(Type)> buffer_;
+  static AlignedMemory<sizeof(Type), ALIGNOF(Type)> buffer_;
   // Signal the object was already deleted, so it is not revived.
-  static base::subtle::Atomic32 dead_;
+  static subtle::Atomic32 dead_;
 };
 
-template <typename Type> base::AlignedMemory<sizeof(Type), ALIGNOF(Type)>
+template <typename Type>
+AlignedMemory<sizeof(Type), ALIGNOF(Type)>
     StaticMemorySingletonTraits<Type>::buffer_;
-template <typename Type> base::subtle::Atomic32
-    StaticMemorySingletonTraits<Type>::dead_ = 0;
+template <typename Type>
+subtle::Atomic32 StaticMemorySingletonTraits<Type>::dead_ = 0;
 
 // The Singleton<Type, Traits, DifferentiatingType> class manages a single
 // instance of Type which will be created on first use and will be destroyed at
@@ -190,7 +189,7 @@
 //   RAE = kRegisterAtExit
 //
 // On every platform, if Traits::RAE is true, the singleton will be destroyed at
-// process exit. More precisely it uses base::AtExitManager which requires an
+// process exit. More precisely it uses AtExitManager which requires an
 // object of this type to be instantiated. AtExitManager mimics the semantics
 // of atexit() such as LIFO order but under Windows is safer to call. For more
 // information see at_exit.h.
@@ -209,6 +208,7 @@
 // (b) Your factory function must never throw an exception. This class is not
 //     exception-safe.
 //
+
 template <typename Type,
           typename Traits = DefaultSingletonTraits<Type>,
           typename DifferentiatingType = Type>
@@ -219,7 +219,7 @@
   friend Type* Type::GetInstance();
 
   // Allow TraceLog tests to test tracing after OnExit.
-  friend class DeleteTraceLogForTesting;
+  friend class internal::DeleteTraceLogForTesting;
 
   // This class is safe to be constructed and copy-constructed since it has no
   // member.
@@ -229,36 +229,36 @@
 #ifndef NDEBUG
     // Avoid making TLS lookup on release builds.
     if (!Traits::kAllowedToAccessOnNonjoinableThread)
-      base::ThreadRestrictions::AssertSingletonAllowed();
+      ThreadRestrictions::AssertSingletonAllowed();
 #endif
 
     // The load has acquire memory ordering as the thread which reads the
     // instance_ pointer must acquire visibility over the singleton data.
-    base::subtle::AtomicWord value = base::subtle::Acquire_Load(&instance_);
-    if (value != 0 && value != base::internal::kBeingCreatedMarker) {
+    subtle::AtomicWord value = subtle::Acquire_Load(&instance_);
+    if (value != 0 && value != internal::kBeingCreatedMarker) {
       return reinterpret_cast<Type*>(value);
     }
 
     // Object isn't created yet, maybe we will get to create it, let's try...
-    if (base::subtle::Acquire_CompareAndSwap(
-          &instance_, 0, base::internal::kBeingCreatedMarker) == 0) {
+    if (subtle::Acquire_CompareAndSwap(&instance_, 0,
+                                       internal::kBeingCreatedMarker) == 0) {
       // instance_ was NULL and is now kBeingCreatedMarker.  Only one thread
       // will ever get here.  Threads might be spinning on us, and they will
       // stop right after we do this store.
       Type* newval = Traits::New();
 
       // Releases the visibility over instance_ to the readers.
-      base::subtle::Release_Store(
-          &instance_, reinterpret_cast<base::subtle::AtomicWord>(newval));
+      subtle::Release_Store(&instance_,
+                            reinterpret_cast<subtle::AtomicWord>(newval));
 
       if (newval != NULL && Traits::kRegisterAtExit)
-        base::AtExitManager::RegisterCallback(OnExit, NULL);
+        AtExitManager::RegisterCallback(OnExit, NULL);
 
       return newval;
     }
 
     // We hit a race. Wait for the other thread to complete it.
-    value = base::internal::WaitForInstance(&instance_);
+    value = internal::WaitForInstance(&instance_);
 
     return reinterpret_cast<Type*>(value);
   }
@@ -269,15 +269,15 @@
   static void OnExit(void* /*unused*/) {
     // AtExit should only ever be register after the singleton instance was
     // created.  We should only ever get here with a valid instance_ pointer.
-    Traits::Delete(
-        reinterpret_cast<Type*>(base::subtle::NoBarrier_Load(&instance_)));
+    Traits::Delete(reinterpret_cast<Type*>(subtle::NoBarrier_Load(&instance_)));
     instance_ = 0;
   }
-  static base::subtle::AtomicWord instance_;
+  static subtle::AtomicWord instance_;
 };
 
 template <typename Type, typename Traits, typename DifferentiatingType>
-base::subtle::AtomicWord Singleton<Type, Traits, DifferentiatingType>::
-    instance_ = 0;
+subtle::AtomicWord Singleton<Type, Traits, DifferentiatingType>::instance_ = 0;
+
+}  // namespace base
 
 #endif  // BASE_MEMORY_SINGLETON_H_
diff --git a/memory/singleton_unittest.cc b/memory/singleton_unittest.cc
index dbff007..e8788ba 100644
--- a/memory/singleton_unittest.cc
+++ b/memory/singleton_unittest.cc
@@ -6,6 +6,7 @@
 #include "base/memory/singleton.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace base {
 namespace {
 
 COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a);
@@ -115,7 +116,7 @@
   ~AlignedTestSingleton() {}
   static AlignedTestSingleton* GetInstance() {
     return Singleton<AlignedTestSingleton,
-        StaticMemorySingletonTraits<AlignedTestSingleton> >::get();
+                     StaticMemorySingletonTraits<AlignedTestSingleton>>::get();
   }
 
   Type type_;
@@ -147,7 +148,6 @@
   return &CallbackSingletonWithStaticTrait::GetInstance()->callback_;
 }
 
-}  // namespace
 
 class SingletonTest : public testing::Test {
  public:
@@ -207,7 +207,7 @@
   CallbackFunc* static_singleton;
 
   {
-    base::ShadowingAtExitManager sem;
+    ShadowingAtExitManager sem;
     {
       singleton_int = SingletonInt();
     }
@@ -241,7 +241,7 @@
   EXPECT_EQ(NULL, GetStaticSingleton());
 
   {
-    base::ShadowingAtExitManager sem;
+    ShadowingAtExitManager sem;
     // Verifiy that the variables were reset.
     {
       singleton_int = SingletonInt();
@@ -285,3 +285,6 @@
   EXPECT_ALIGNED(align128, 128);
   EXPECT_ALIGNED(align4096, 4096);
 }
+
+}  // namespace
+}  // namespace base
diff --git a/numerics/safe_conversions_impl.h b/numerics/safe_conversions_impl.h
index 4157067..f4bc916 100644
--- a/numerics/safe_conversions_impl.h
+++ b/numerics/safe_conversions_impl.h
@@ -108,6 +108,55 @@
                             (is_in_lower_bound ? 0 : RANGE_UNDERFLOW));
 }
 
+// The following helper template addresses a corner case in range checks for
+// conversion from a floating-point type to an integral type of smaller range
+// but larger precision (e.g. float -> unsigned). The problem is as follows:
+//   1. Integral maximum is always one less than a power of two, so it must be
+//      truncated to fit the mantissa of the floating point. The direction of
+//      rounding is implementation defined, but by default it's always IEEE
+//      floats, which round to nearest and thus result in a value of larger
+//      magnitude than the integral value.
+//      Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX
+//                                   // is 4294967295u.
+//   2. If the floating point value is equal to the promoted integral maximum
+//      value, a range check will erroneously pass.
+//      Example: (4294967296f <= 4294967295u) // This is true due to a precision
+//                                            // loss in rounding up to float.
+//   3. When the floating point value is then converted to an integral, the
+//      resulting value is out of range for the target integral type and
+//      thus is implementation defined.
+//      Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0.
+// To fix this bug we manually truncate the maximum value when the destination
+// type is an integral of larger precision than the source floating-point type,
+// such that the resulting maximum is represented exactly as a floating point.
+template <typename Dst, typename Src>
+struct NarrowingRange {
+  typedef typename std::numeric_limits<Src> SrcLimits;
+  typedef typename std::numeric_limits<Dst> DstLimits;
+
+  static Dst max() {
+    // The following logic avoids warnings where the max function is
+    // instantiated with invalid values for a bit shift (even though
+    // such a function can never be called).
+    static const int shift =
+        (MaxExponent<Src>::value > MaxExponent<Dst>::value &&
+         SrcLimits::digits < DstLimits::digits && SrcLimits::is_iec559 &&
+         DstLimits::is_integer)
+            ? (DstLimits::digits - SrcLimits::digits)
+            : 0;
+
+    // We use UINTMAX_C below to avoid compiler warnings about shifting floating
+    // points. Since it's a compile time calculation, it shouldn't have any
+    // performance impact.
+    return DstLimits::max() - static_cast<Dst>((UINTMAX_C(1) << shift) - 1);
+  }
+
+  static Dst min() {
+    return std::numeric_limits<Dst>::is_iec559 ? -DstLimits::max()
+                                               : DstLimits::min();
+  }
+};
+
 template <
     typename Dst,
     typename Src,
@@ -147,11 +196,8 @@
                                       INTEGER_REPRESENTATION_SIGNED,
                                       NUMERIC_RANGE_NOT_CONTAINED> {
   static RangeConstraint Check(Src value) {
-    return std::numeric_limits<Dst>::is_iec559
-               ? GetRangeConstraint((value < std::numeric_limits<Dst>::max()),
-                                    (value > -std::numeric_limits<Dst>::max()))
-               : GetRangeConstraint((value < std::numeric_limits<Dst>::max()),
-                                    (value > std::numeric_limits<Dst>::min()));
+    return GetRangeConstraint((value <= NarrowingRange<Dst, Src>::max()),
+                              (value >= NarrowingRange<Dst, Src>::min()));
   }
 };
 
@@ -163,7 +209,7 @@
                                       INTEGER_REPRESENTATION_UNSIGNED,
                                       NUMERIC_RANGE_NOT_CONTAINED> {
   static RangeConstraint Check(Src value) {
-    return GetRangeConstraint(value < std::numeric_limits<Dst>::max(), true);
+    return GetRangeConstraint(value <= NarrowingRange<Dst, Src>::max(), true);
   }
 };
 
@@ -178,7 +224,7 @@
     return sizeof(Dst) > sizeof(Src)
                ? RANGE_VALID
                : GetRangeConstraint(
-                     value < static_cast<Src>(std::numeric_limits<Dst>::max()),
+                     value <= static_cast<Src>(NarrowingRange<Dst, Src>::max()),
                      true);
   }
 };
@@ -195,7 +241,7 @@
     return (MaxExponent<Dst>::value >= MaxExponent<Src>::value)
                ? GetRangeConstraint(true, value >= static_cast<Src>(0))
                : GetRangeConstraint(
-                     value < static_cast<Src>(std::numeric_limits<Dst>::max()),
+                     value <= static_cast<Src>(NarrowingRange<Dst, Src>::max()),
                      value >= static_cast<Src>(0));
   }
 };
diff --git a/numerics/safe_numerics_unittest.cc b/numerics/safe_numerics_unittest.cc
index 6f9a966..bad0f57 100644
--- a/numerics/safe_numerics_unittest.cc
+++ b/numerics/safe_numerics_unittest.cc
@@ -18,6 +18,7 @@
 using std::numeric_limits;
 using base::CheckedNumeric;
 using base::checked_cast;
+using base::IsValueInRangeForNumericType;
 using base::SizeT;
 using base::StrictNumeric;
 using base::saturated_cast;
@@ -36,6 +37,26 @@
 #pragma warning(disable:4756)
 #endif
 
+// This is a helper function for finding the maximum value in Src that can be
+// wholy represented as the destination floating-point type.
+template <typename Dst, typename Src>
+Dst GetMaxConvertibleToFloat() {
+  typedef numeric_limits<Dst> DstLimits;
+  typedef numeric_limits<Src> SrcLimits;
+  static_assert(SrcLimits::is_specialized, "Source must be numeric.");
+  static_assert(DstLimits::is_specialized, "Destination must be numeric.");
+  CHECK(DstLimits::is_iec559);
+
+  if (SrcLimits::digits <= DstLimits::digits &&
+      MaxExponent<Src>::value <= MaxExponent<Dst>::value)
+    return SrcLimits::max();
+  Src max = SrcLimits::max() / 2 + (SrcLimits::is_integer ? 1 : 0);
+  while (max != static_cast<Src>(static_cast<Dst>(max))) {
+    max /= 2;
+  }
+  return static_cast<Dst>(max);
+}
+
 // Helper macros to wrap displaying the conversion types and line numbers.
 #define TEST_EXPECTED_VALIDITY(expected, actual)                           \
   EXPECT_EQ(expected, CheckedNumeric<Dst>(actual).validity())              \
@@ -370,6 +391,18 @@
       TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity());
       TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1);
       TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN());
+      if (DstLimits::is_integer) {
+        if (SrcLimits::digits < DstLimits::digits) {
+          TEST_EXPECTED_RANGE(RANGE_OVERFLOW,
+                              static_cast<Src>(DstLimits::max()));
+        } else {
+          TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::max()));
+        }
+        TEST_EXPECTED_RANGE(
+            RANGE_VALID,
+            static_cast<Src>(GetMaxConvertibleToFloat<Src, Dst>()));
+        TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::min()));
+      }
     } else if (SrcLimits::is_signed) {
       TEST_EXPECTED_VALUE(-1, checked_dst - static_cast<Src>(1));
       TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min());
@@ -428,6 +461,18 @@
       TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity());
       TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1);
       TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN());
+      if (DstLimits::is_integer) {
+        if (SrcLimits::digits < DstLimits::digits) {
+          TEST_EXPECTED_RANGE(RANGE_OVERFLOW,
+                              static_cast<Src>(DstLimits::max()));
+        } else {
+          TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::max()));
+        }
+        TEST_EXPECTED_RANGE(
+            RANGE_VALID,
+            static_cast<Src>(GetMaxConvertibleToFloat<Src, Dst>()));
+        TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::min()));
+      }
     } else {
       TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min());
     }
@@ -600,3 +645,77 @@
   EXPECT_EQ(numeric_limits<int>::max(), saturated_cast<int>(double_large_int));
 }
 
+TEST(SafeNumerics, IsValueInRangeForNumericType) {
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(0));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(2));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(-1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(0xffffffffu));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0xffffffff)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0x100000000)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0x100000001)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(
+      std::numeric_limits<int32_t>::min()));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(
+      std::numeric_limits<int64_t>::min()));
+
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(2));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(-1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0x7fffffff));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0x7fffffffu));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(0x80000000u));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(0xffffffffu));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0x80000000)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0xffffffff)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0x100000000)));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(
+      std::numeric_limits<int32_t>::min()));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(
+      implicit_cast<int64_t>(std::numeric_limits<int32_t>::min())));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(
+      implicit_cast<int64_t>(std::numeric_limits<int32_t>::min()) - 1));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(
+      std::numeric_limits<int64_t>::min()));
+
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(0));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(2));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(-1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(0xffffffffu));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0xffffffff)));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0x100000000)));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0x100000001)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(
+      std::numeric_limits<int32_t>::min()));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(INT64_C(-1)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(
+      std::numeric_limits<int64_t>::min()));
+
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(2));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(-1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x7fffffff));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x7fffffffu));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x80000000u));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0xffffffffu));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0x80000000)));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0xffffffff)));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0x100000000)));
+  EXPECT_TRUE(
+      IsValueInRangeForNumericType<int64_t>(INT64_C(0x7fffffffffffffff)));
+  EXPECT_TRUE(
+      IsValueInRangeForNumericType<int64_t>(UINT64_C(0x7fffffffffffffff)));
+  EXPECT_FALSE(
+      IsValueInRangeForNumericType<int64_t>(UINT64_C(0x8000000000000000)));
+  EXPECT_FALSE(
+      IsValueInRangeForNumericType<int64_t>(UINT64_C(0xffffffffffffffff)));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(
+      std::numeric_limits<int32_t>::min()));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(
+      implicit_cast<int64_t>(std::numeric_limits<int32_t>::min())));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(
+      std::numeric_limits<int64_t>::min()));
+}
diff --git a/process/launch_posix.cc b/process/launch_posix.cc
index 96685cb..6c2f779 100644
--- a/process/launch_posix.cc
+++ b/process/launch_posix.cc
@@ -22,7 +22,6 @@
 #include <limits>
 #include <set>
 
-#include "base/allocator/type_profiler_control.h"
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/debug/debugger.h"
@@ -392,11 +391,6 @@
       }
     }
 
-    // Stop type-profiler.
-    // The profiler should be stopped between fork and exec since it inserts
-    // locks at new/delete expressions.  See http://crbug.com/36678.
-    base::type_profiler::Controller::Stop();
-
     if (options.maximize_rlimits) {
       // Some resource limits need to be maximal in this child.
       for (size_t i = 0; i < options.maximize_rlimits->size(); ++i) {
@@ -593,11 +587,6 @@
         if (dev_null < 0)
           _exit(127);
 
-        // Stop type-profiler.
-        // The profiler should be stopped between fork and exec since it inserts
-        // locks at new/delete expressions.  See http://crbug.com/36678.
-        base::type_profiler::Controller::Stop();
-
         fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true));
         fd_shuffle1.push_back(InjectionArc(
             include_stderr ? pipe_fd[1] : dev_null, STDERR_FILENO, true));
diff --git a/sync_socket.h b/sync_socket.h
index 36d6bc1..201fb1c 100644
--- a/sync_socket.h
+++ b/sync_socket.h
@@ -83,10 +83,8 @@
                                     TimeDelta timeout);
 
   // Returns the number of bytes available. If non-zero, Receive() will not
-  // not block when called. NOTE: Some implementations cannot reliably
-  // determine the number of bytes available so avoid using the returned
-  // size as a promise and simply test against zero.
-  size_t Peek();
+  // not block when called.
+  virtual size_t Peek();
 
   // Extracts the contained handle.  Used for transferring between
   // processes.
diff --git a/synchronization/condition_variable.h b/synchronization/condition_variable.h
index 5d8507d..91e4d13 100644
--- a/synchronization/condition_variable.h
+++ b/synchronization/condition_variable.h
@@ -73,6 +73,7 @@
 
 #include "base/base_export.h"
 #include "base/basictypes.h"
+#include "base/logging.h"
 #include "base/synchronization/lock.h"
 
 namespace base {
@@ -104,7 +105,7 @@
 #elif defined(OS_POSIX)
   pthread_cond_t condition_;
   pthread_mutex_t* user_mutex_;
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
   base::Lock* user_lock_;     // Needed to adjust shadow lock state on wait.
 #endif
 
diff --git a/synchronization/condition_variable_posix.cc b/synchronization/condition_variable_posix.cc
index c9a2ec4..03f8184 100644
--- a/synchronization/condition_variable_posix.cc
+++ b/synchronization/condition_variable_posix.cc
@@ -7,7 +7,6 @@
 #include <errno.h>
 #include <sys/time.h>
 
-#include "base/logging.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
@@ -16,8 +15,9 @@
 
 ConditionVariable::ConditionVariable(Lock* user_lock)
     : user_mutex_(user_lock->lock_.native_handle())
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
-    , user_lock_(user_lock)
+#if DCHECK_IS_ON()
+      ,
+      user_lock_(user_lock)
 #endif
 {
   int rv = 0;
@@ -62,12 +62,12 @@
 
 void ConditionVariable::Wait() {
   base::ThreadRestrictions::AssertWaitAllowed();
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
   user_lock_->CheckHeldAndUnmark();
 #endif
   int rv = pthread_cond_wait(&condition_, user_mutex_);
   DCHECK_EQ(0, rv);
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
   user_lock_->CheckUnheldAndMark();
 #endif
 }
@@ -80,7 +80,7 @@
   relative_time.tv_nsec =
       (usecs % Time::kMicrosecondsPerSecond) * Time::kNanosecondsPerMicrosecond;
 
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
   user_lock_->CheckHeldAndUnmark();
 #endif
 
@@ -118,7 +118,7 @@
 #endif  // OS_MACOSX
 
   DCHECK(rv == 0 || rv == ETIMEDOUT);
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
   user_lock_->CheckUnheldAndMark();
 #endif
 }
diff --git a/synchronization/condition_variable_win.cc b/synchronization/condition_variable_win.cc
index 470e564..4256ac8 100644
--- a/synchronization/condition_variable_win.cc
+++ b/synchronization/condition_variable_win.cc
@@ -8,7 +8,6 @@
 #include <stack>
 
 #include "base/compiler_specific.h"
-#include "base/logging.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
@@ -99,7 +98,7 @@
   DWORD timeout = static_cast<DWORD>(max_time.InMilliseconds());
   CRITICAL_SECTION* cs = user_lock_.lock_.native_handle();
 
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
   user_lock_.CheckHeldAndUnmark();
 #endif
 
diff --git a/synchronization/lock.cc b/synchronization/lock.cc
index b1576c5..03297ad 100644
--- a/synchronization/lock.cc
+++ b/synchronization/lock.cc
@@ -6,10 +6,9 @@
 // is functionally a wrapper around the LockImpl class, so the only
 // real intelligence in the class is in the debugging logic.
 
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
-
 #include "base/synchronization/lock.h"
-#include "base/logging.h"
+
+#if DCHECK_IS_ON()
 
 namespace base {
 
@@ -36,4 +35,4 @@
 
 }  // namespace base
 
-#endif  // !NDEBUG || DCHECK_ALWAYS_ON
+#endif  // DCHECK_IS_ON()
diff --git a/synchronization/lock.h b/synchronization/lock.h
index f384e41..b6afecb 100644
--- a/synchronization/lock.h
+++ b/synchronization/lock.h
@@ -6,6 +6,7 @@
 #define BASE_SYNCHRONIZATION_LOCK_H_
 
 #include "base/base_export.h"
+#include "base/logging.h"
 #include "base/synchronization/lock_impl.h"
 #include "base/threading/platform_thread.h"
 
@@ -16,8 +17,8 @@
 // AssertAcquired() method.
 class BASE_EXPORT Lock {
  public:
-#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
-   // Optimized wrapper implementation
+#if !DCHECK_IS_ON()
+  // Optimized wrapper implementation
   Lock() : lock_() {}
   ~Lock() {}
   void Acquire() { lock_.Lock(); }
@@ -56,7 +57,7 @@
   }
 
   void AssertAcquired() const;
-#endif  // NDEBUG && !DCHECK_ALWAYS_ON
+#endif  // DCHECK_IS_ON()
 
 #if defined(OS_POSIX)
   // The posix implementation of ConditionVariable needs to be able
@@ -70,7 +71,7 @@
 #endif
 
  private:
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
   // Members and routines taking care of locks assertions.
   // Note that this checks for recursive locks and allows them
   // if the variable is set.  This is allowed by the underlying implementation
@@ -82,7 +83,7 @@
   // All private data is implicitly protected by lock_.
   // Be VERY careful to only access members under that lock.
   base::PlatformThreadRef owning_thread_ref_;
-#endif  // !NDEBUG || DCHECK_ALWAYS_ON
+#endif  // DCHECK_IS_ON()
 
   // Platform specific underlying lock implementation.
   internal::LockImpl lock_;
diff --git a/test/test_support_android.cc b/test/test_support_android.cc
index 11a0871..5a02ef0 100644
--- a/test/test_support_android.cc
+++ b/test/test_support_android.cc
@@ -39,27 +39,21 @@
 // when there are no pending messages.
 class Waitable {
  public:
-   static Waitable* GetInstance() {
-     return Singleton<Waitable>::get();
-   }
+  static Waitable* GetInstance() { return base::Singleton<Waitable>::get(); }
 
-   // Signals that there are more work to do.
-   void Signal() {
-     waitable_event_.Signal();
-   }
+  // Signals that there are more work to do.
+  void Signal() { waitable_event_.Signal(); }
 
-   // Blocks until more work is scheduled.
-   void Block() {
-     waitable_event_.Wait();
-   }
+  // Blocks until more work is scheduled.
+  void Block() { waitable_event_.Wait(); }
 
-   void Quit() {
-     g_state->should_quit = true;
-     Signal();
+  void Quit() {
+    g_state->should_quit = true;
+    Signal();
    }
 
  private:
-  friend struct DefaultSingletonTraits<Waitable>;
+  friend struct base::DefaultSingletonTraits<Waitable>;
 
   Waitable()
       : waitable_event_(false, false) {
diff --git a/threading/thread_id_name_manager.h b/threading/thread_id_name_manager.h
index 927d25f..1ba7e13 100644
--- a/threading/thread_id_name_manager.h
+++ b/threading/thread_id_name_manager.h
@@ -13,10 +13,11 @@
 #include "base/synchronization/lock.h"
 #include "base/threading/platform_thread.h"
 
-template <typename T> struct DefaultSingletonTraits;
-
 namespace base {
 
+template <typename T>
+struct DefaultSingletonTraits;
+
 class BASE_EXPORT ThreadIdNameManager {
  public:
   static ThreadIdNameManager* GetInstance();
diff --git a/threading/thread_restrictions.cc b/threading/thread_restrictions.cc
index 871f2dc..00306c5 100644
--- a/threading/thread_restrictions.cc
+++ b/threading/thread_restrictions.cc
@@ -23,7 +23,7 @@
 LazyInstance<ThreadLocalBoolean>::Leaky
     g_wait_disallowed = LAZY_INSTANCE_INITIALIZER;
 
-}  // anonymous namespace
+}  // namespace
 
 // static
 bool ThreadRestrictions::SetIOAllowed(bool allowed) {
@@ -69,7 +69,7 @@
 // static
 void ThreadRestrictions::AssertWaitAllowed() {
   if (g_wait_disallowed.Get().Get()) {
-    LOG(FATAL) << "Waiting is not allowed to be used on this thread to prevent"
+    LOG(FATAL) << "Waiting is not allowed to be used on this thread to prevent "
                << "jank and deadlock.";
   }
 }
diff --git a/trace_event/BUILD.gn b/trace_event/BUILD.gn
index 09c9380..a4e1e43 100644
--- a/trace_event/BUILD.gn
+++ b/trace_event/BUILD.gn
@@ -105,6 +105,7 @@
     "process_memory_dump_unittest.cc",
     "process_memory_maps_dump_provider_unittest.cc",
     "process_memory_totals_dump_provider_unittest.cc",
+    "trace_config_memory_test_util.h",
     "trace_config_unittest.cc",
     "trace_event_argument_unittest.cc",
     "trace_event_memory_unittest.cc",
diff --git a/trace_event/java_heap_dump_provider_android_unittest.cc b/trace_event/java_heap_dump_provider_android_unittest.cc
index 557ac45..35f3f17 100644
--- a/trace_event/java_heap_dump_provider_android_unittest.cc
+++ b/trace_event/java_heap_dump_provider_android_unittest.cc
@@ -13,7 +13,7 @@
 TEST(JavaHeapDumpProviderTest, JavaHeapDump) {
   auto jhdp = JavaHeapDumpProvider::GetInstance();
   scoped_ptr<ProcessMemoryDump> pmd(new ProcessMemoryDump(nullptr));
-  MemoryDumpArgs dump_args = {MemoryDumpArgs::LevelOfDetail::HIGH};
+  MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
 
   jhdp->OnMemoryDump(dump_args, pmd.get());
 }
diff --git a/trace_event/malloc_dump_provider.cc b/trace_event/malloc_dump_provider.cc
index 98b53da..7cdc34a 100644
--- a/trace_event/malloc_dump_provider.cc
+++ b/trace_event/malloc_dump_provider.cc
@@ -39,7 +39,7 @@
   // dlmalloc the total is given by |arena| + |hblkhd|.
   // For more details see link: http://goo.gl/fMR8lF.
   MemoryAllocatorDump* outer_dump = pmd->CreateAllocatorDump("malloc");
-  outer_dump->AddScalar("heap_virtual_size", MemoryAllocatorDump::kUnitsBytes,
+  outer_dump->AddScalar("virtual_size", MemoryAllocatorDump::kUnitsBytes,
                         info.arena + info.hblkhd);
 
   // Total allocated space is given by |uordblks|.
diff --git a/trace_event/memory_allocator_dump.cc b/trace_event/memory_allocator_dump.cc
index 4037f94..76d53eb 100644
--- a/trace_event/memory_allocator_dump.cc
+++ b/trace_event/memory_allocator_dump.cc
@@ -16,7 +16,7 @@
 namespace trace_event {
 
 const char MemoryAllocatorDump::kNameSize[] = "size";
-const char MemoryAllocatorDump::kNameObjectsCount[] = "objects_count";
+const char MemoryAllocatorDump::kNameObjectCount[] = "object_count";
 const char MemoryAllocatorDump::kTypeScalar[] = "scalar";
 const char MemoryAllocatorDump::kTypeString[] = "string";
 const char MemoryAllocatorDump::kUnitsBytes[] = "bytes";
diff --git a/trace_event/memory_allocator_dump.h b/trace_event/memory_allocator_dump.h
index 2ded173..6ad3d64 100644
--- a/trace_event/memory_allocator_dump.h
+++ b/trace_event/memory_allocator_dump.h
@@ -34,7 +34,7 @@
 
   // Standard attribute |name|s for the AddScalar and AddString() methods.
   static const char kNameSize[];          // To represent allocated space.
-  static const char kNameObjectsCount[];  // To represent number of objects.
+  static const char kNameObjectCount[];   // To represent number of objects.
 
   // Standard attribute |unit|s for the AddScalar and AddString() methods.
   static const char kUnitsBytes[];    // Unit name to represent bytes.
diff --git a/trace_event/memory_allocator_dump_unittest.cc b/trace_event/memory_allocator_dump_unittest.cc
index 8a41513..f787e64 100644
--- a/trace_event/memory_allocator_dump_unittest.cc
+++ b/trace_event/memory_allocator_dump_unittest.cc
@@ -28,7 +28,7 @@
 
     root_heap->AddScalar(MemoryAllocatorDump::kNameSize,
                          MemoryAllocatorDump::kUnitsBytes, 4096);
-    root_heap->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+    root_heap->AddScalar(MemoryAllocatorDump::kNameObjectCount,
                          MemoryAllocatorDump::kUnitsObjects, 42);
     root_heap->AddScalar("attr1", "units1", 1234);
     root_heap->AddString("attr2", "units2", "string_value");
@@ -38,7 +38,7 @@
         pmd->CreateAllocatorDump("foobar_allocator/sub_heap");
     sub_heap->AddScalar(MemoryAllocatorDump::kNameSize,
                         MemoryAllocatorDump::kUnitsBytes, 1);
-    sub_heap->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+    sub_heap->AddScalar(MemoryAllocatorDump::kNameObjectCount,
                         MemoryAllocatorDump::kUnitsObjects, 3);
 
     pmd->CreateAllocatorDump("foobar_allocator/sub_heap/empty");
@@ -126,7 +126,7 @@
 TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) {
   FakeMemoryAllocatorDumpProvider fmadp;
   ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
-  MemoryDumpArgs dump_args = {MemoryDumpArgs::LevelOfDetail::HIGH};
+  MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
 
   fmadp.OnMemoryDump(dump_args, &pmd);
 
@@ -138,7 +138,7 @@
   EXPECT_EQ("foobar_allocator", root_heap->absolute_name());
   CheckScalar(root_heap, MemoryAllocatorDump::kNameSize,
               MemoryAllocatorDump::kUnitsBytes, 4096);
-  CheckScalar(root_heap, MemoryAllocatorDump::kNameObjectsCount,
+  CheckScalar(root_heap, MemoryAllocatorDump::kNameObjectCount,
               MemoryAllocatorDump::kUnitsObjects, 42);
   CheckScalar(root_heap, "attr1", "units1", 1234);
   CheckString(root_heap, "attr2", MemoryAllocatorDump::kTypeString, "units2",
@@ -151,7 +151,7 @@
   EXPECT_EQ("foobar_allocator/sub_heap", sub_heap->absolute_name());
   CheckScalar(sub_heap, MemoryAllocatorDump::kNameSize,
               MemoryAllocatorDump::kUnitsBytes, 1);
-  CheckScalar(sub_heap, MemoryAllocatorDump::kNameObjectsCount,
+  CheckScalar(sub_heap, MemoryAllocatorDump::kNameObjectCount,
               MemoryAllocatorDump::kUnitsObjects, 3);
   const MemoryAllocatorDump* empty_sub_heap =
       pmd.GetAllocatorDump("foobar_allocator/sub_heap/empty");
@@ -161,7 +161,7 @@
   DictionaryValue* attrs = nullptr;
   ASSERT_TRUE(raw_attrs->GetAsDictionary(&attrs));
   ASSERT_FALSE(attrs->HasKey(MemoryAllocatorDump::kNameSize));
-  ASSERT_FALSE(attrs->HasKey(MemoryAllocatorDump::kNameObjectsCount));
+  ASSERT_FALSE(attrs->HasKey(MemoryAllocatorDump::kNameObjectCount));
 
   // Check that the AsValueInfo doesn't hit any DCHECK.
   scoped_refptr<TracedValue> traced_value(new TracedValue());
diff --git a/trace_event/memory_dump_manager.cc b/trace_event/memory_dump_manager.cc
index 71a9dae..1c10d1c 100644
--- a/trace_event/memory_dump_manager.cc
+++ b/trace_event/memory_dump_manager.cc
@@ -48,21 +48,20 @@
 MemoryDumpManager* g_instance_for_testing = nullptr;
 
 void RequestPeriodicGlobalDump() {
-  MemoryDumpArgs::LevelOfDetail dump_level_of_detail;
+  MemoryDumpLevelOfDetail level_of_detail;
   if (g_heavy_dumps_rate == 0) {
-    dump_level_of_detail = MemoryDumpArgs::LevelOfDetail::LOW;
+    level_of_detail = MemoryDumpLevelOfDetail::LIGHT;
   } else {
-    dump_level_of_detail = g_periodic_dumps_count == 0
-                               ? MemoryDumpArgs::LevelOfDetail::HIGH
-                               : MemoryDumpArgs::LevelOfDetail::LOW;
+    level_of_detail = g_periodic_dumps_count == 0
+                          ? MemoryDumpLevelOfDetail::DETAILED
+                          : MemoryDumpLevelOfDetail::LIGHT;
 
     if (++g_periodic_dumps_count == g_heavy_dumps_rate)
       g_periodic_dumps_count = 0;
   }
 
-  MemoryDumpArgs dump_args = {dump_level_of_detail};
   MemoryDumpManager::GetInstance()->RequestGlobalDump(
-      MemoryDumpType::PERIODIC_INTERVAL, dump_args);
+      MemoryDumpType::PERIODIC_INTERVAL, level_of_detail);
 }
 
 }  // namespace
@@ -78,6 +77,16 @@
 const uint64 MemoryDumpManager::kInvalidTracingProcessId = 0;
 
 // static
+const char* const MemoryDumpManager::kSystemAllocatorPoolName =
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+    MallocDumpProvider::kAllocatedObjects;
+#elif defined(OS_WIN)
+    WinHeapDumpProvider::kAllocatedObjects;
+#else
+    nullptr;
+#endif
+
+// static
 MemoryDumpManager* MemoryDumpManager::GetInstance() {
   if (g_instance_for_testing)
     return g_instance_for_testing;
@@ -95,50 +104,54 @@
 
 MemoryDumpManager::MemoryDumpManager()
     : delegate_(nullptr),
+      is_coordinator_(false),
       memory_tracing_enabled_(0),
       tracing_process_id_(kInvalidTracingProcessId),
-      system_allocator_pool_name_(nullptr),
-      skip_core_dumpers_auto_registration_for_testing_(false),
-      disable_periodic_dumps_for_testing_(false) {
+      skip_core_dumpers_auto_registration_for_testing_(false) {
   g_next_guid.GetNext();  // Make sure that first guid is not zero.
 }
 
 MemoryDumpManager::~MemoryDumpManager() {
-  base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
 }
 
-void MemoryDumpManager::Initialize() {
-  TRACE_EVENT0(kTraceCategory, "init");  // Add to trace-viewer category list.
-  trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this);
-
-  if (skip_core_dumpers_auto_registration_for_testing_)
-    return;
+void MemoryDumpManager::Initialize(MemoryDumpManagerDelegate* delegate,
+                                   bool is_coordinator) {
+  {
+    AutoLock lock(lock_);
+    DCHECK(delegate);
+    DCHECK(!delegate_);
+    delegate_ = delegate;
+    is_coordinator_ = is_coordinator;
+  }
 
   // Enable the core dump providers.
+  if (!skip_core_dumpers_auto_registration_for_testing_) {
 #if !defined(OS_NACL)
-  RegisterDumpProvider(ProcessMemoryTotalsDumpProvider::GetInstance());
+    RegisterDumpProvider(ProcessMemoryTotalsDumpProvider::GetInstance());
 #endif
 
 #if (defined(OS_LINUX) && !defined(FNL_MUSL)) || defined(OS_ANDROID)
-  RegisterDumpProvider(ProcessMemoryMapsDumpProvider::GetInstance());
-  RegisterDumpProvider(MallocDumpProvider::GetInstance());
-  system_allocator_pool_name_ = MallocDumpProvider::kAllocatedObjects;
+    RegisterDumpProvider(ProcessMemoryMapsDumpProvider::GetInstance());
+    RegisterDumpProvider(MallocDumpProvider::GetInstance());
 #endif
 
 #if defined(OS_ANDROID)
-  RegisterDumpProvider(JavaHeapDumpProvider::GetInstance());
+    RegisterDumpProvider(JavaHeapDumpProvider::GetInstance());
 #endif
 
 #if defined(OS_WIN)
-  RegisterDumpProvider(WinHeapDumpProvider::GetInstance());
-  system_allocator_pool_name_ = WinHeapDumpProvider::kAllocatedObjects;
+    RegisterDumpProvider(WinHeapDumpProvider::GetInstance());
 #endif
-}
+  }  // !skip_core_dumpers_auto_registration_for_testing_
 
-void MemoryDumpManager::SetDelegate(MemoryDumpManagerDelegate* delegate) {
-  AutoLock lock(lock_);
-  DCHECK_EQ(static_cast<MemoryDumpManagerDelegate*>(nullptr), delegate_);
-  delegate_ = delegate;
+  // If tracing was enabled before initializing MemoryDumpManager, we missed the
+  // OnTraceLogEnabled() event. Synthetize it so we can late-join the party.
+  bool is_tracing_already_enabled = TraceLog::GetInstance()->IsEnabled();
+  TRACE_EVENT0(kTraceCategory, "init");  // Add to trace-viewer category list.
+  TraceLog::GetInstance()->AddEnabledStateObserver(this);
+  if (is_tracing_already_enabled)
+    OnTraceLogEnabled();
 }
 
 void MemoryDumpManager::RegisterDumpProvider(
@@ -189,9 +202,10 @@
   mdp_iter->unregistered = true;
 }
 
-void MemoryDumpManager::RequestGlobalDump(MemoryDumpType dump_type,
-                                          const MemoryDumpArgs& dump_args,
-                                          const MemoryDumpCallback& callback) {
+void MemoryDumpManager::RequestGlobalDump(
+    MemoryDumpType dump_type,
+    MemoryDumpLevelOfDetail level_of_detail,
+    const MemoryDumpCallback& callback) {
   // Bail out immediately if tracing is not enabled at all.
   if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_))) {
     if (!callback.is_null())
@@ -202,27 +216,27 @@
   const uint64 guid =
       TraceLog::GetInstance()->MangleEventId(g_next_guid.GetNext());
 
-  // The delegate_ is supposed to be thread safe, immutable and long lived.
-  // No need to keep the lock after we ensure that a delegate has been set.
+  // Technically there is no need to grab the |lock_| here as the delegate is
+  // long-lived and can only be set by Initialize(), which is locked and
+  // necessarily happens before memory_tracing_enabled_ == true.
+  // Not taking the |lock_|, though, is lakely make TSan barf and, at this point
+  // (memory-infra is enabled) we're not in the fast-path anymore.
   MemoryDumpManagerDelegate* delegate;
   {
     AutoLock lock(lock_);
     delegate = delegate_;
   }
 
-  if (delegate) {
-    // The delegate is in charge to coordinate the request among all the
-    // processes and call the CreateLocalDumpPoint on the local process.
-    MemoryDumpRequestArgs args = {guid, dump_type, dump_args};
-    delegate->RequestGlobalMemoryDump(args, callback);
-  } else if (!callback.is_null()) {
-    callback.Run(guid, false /* success */);
-  }
+  // The delegate will coordinate the IPC broadcast and at some point invoke
+  // CreateProcessDump() to get a dump for the current process.
+  MemoryDumpRequestArgs args = {guid, dump_type, level_of_detail};
+  delegate->RequestGlobalMemoryDump(args, callback);
 }
 
-void MemoryDumpManager::RequestGlobalDump(MemoryDumpType dump_type,
-                                          const MemoryDumpArgs& dump_args) {
-  RequestGlobalDump(dump_type, dump_args, MemoryDumpCallback());
+void MemoryDumpManager::RequestGlobalDump(
+    MemoryDumpType dump_type,
+    MemoryDumpLevelOfDetail level_of_detail) {
+  RequestGlobalDump(dump_type, level_of_detail, MemoryDumpCallback());
 }
 
 void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args,
@@ -305,8 +319,9 @@
   bool dump_successful = false;
 
   if (!skip_dump) {
-    dump_successful = mdp->OnMemoryDump(pmd_async_state->req_args.dump_args,
-                                        &pmd_async_state->process_memory_dump);
+    MemoryDumpArgs args = {pmd_async_state->req_args.level_of_detail};
+    dump_successful =
+        mdp->OnMemoryDump(args, &pmd_async_state->process_memory_dump);
   }
 
   {
@@ -386,11 +401,10 @@
 }
 
 void MemoryDumpManager::OnTraceLogEnabled() {
-  // TODO(primiano): at this point we query  TraceLog::GetCurrentCategoryFilter
-  // to figure out (and cache) which dumpers should be enabled or not.
-  // For the moment piggy back everything on the generic "memory" category.
   bool enabled;
   TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled);
+  if (!enabled)
+    return;
 
   // Initialize the TraceLog for the current thread. This is to avoid that the
   // TraceLog memory dump provider is registered lazily in the PostTask() below
@@ -399,13 +413,7 @@
 
   AutoLock lock(lock_);
 
-  // There is no point starting the tracing without a delegate.
-  if (!enabled || !delegate_) {
-    // Disable all the providers.
-    for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it)
-      it->disabled = true;
-    return;
-  }
+  DCHECK(delegate_);  // At this point we must have a delegate.
 
   session_state_ = new MemoryDumpSessionState();
   for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it) {
@@ -417,12 +425,10 @@
 
   // TODO(primiano): This is a temporary hack to disable periodic memory dumps
   // when running memory benchmarks until telemetry uses TraceConfig to
-  // enable/disable periodic dumps.
-  // The same mechanism should be used to disable periodic dumps in tests.
-  if (!delegate_->IsCoordinatorProcess() ||
+  // enable/disable periodic dumps. See crbug.com/529184 .
+  if (!is_coordinator_ ||
       CommandLine::ForCurrentProcess()->HasSwitch(
-          "enable-memory-benchmarking") ||
-      disable_periodic_dumps_for_testing_) {
+          "enable-memory-benchmarking")) {
     return;
   }
 
@@ -443,7 +449,7 @@
   DCHECK_LE(config_list.size(), 2u);
   for (const TraceConfig::MemoryDumpTriggerConfig& config : config_list) {
     DCHECK(config.periodic_interval_ms);
-    if (config.level_of_detail == MemoryDumpArgs::LevelOfDetail::HIGH)
+    if (config.level_of_detail == MemoryDumpLevelOfDetail::DETAILED)
       heavy_dump_period_ms = config.periodic_interval_ms;
     min_timer_period_ms =
         std::min(min_timer_period_ms, config.periodic_interval_ms);
diff --git a/trace_event/memory_dump_manager.h b/trace_event/memory_dump_manager.h
index 305ec59..b445cdb 100644
--- a/trace_event/memory_dump_manager.h
+++ b/trace_event/memory_dump_manager.h
@@ -40,12 +40,19 @@
 
   static MemoryDumpManager* GetInstance();
 
-  // Invoked once per process to register the TraceLog observer.
-  void Initialize();
-
-  // See the lifetime and thread-safety requirements on the delegate below in
-  // the |MemoryDumpManagerDelegate| docstring.
-  void SetDelegate(MemoryDumpManagerDelegate* delegate);
+  // Invoked once per process to listen to trace begin / end events.
+  // Initialization can happen after (Un)RegisterMemoryDumpProvider() calls
+  // and the MemoryDumpManager guarantees to support this.
+  // On the other side, the MemoryDumpManager will not be fully operational
+  // (i.e. will NACK any RequestGlobalMemoryDump()) until initialized.
+  // Arguments:
+  //  is_coordinator: if true this MemoryDumpManager instance will act as a
+  //      coordinator and schedule periodic dumps (if enabled via TraceConfig);
+  //      false when the MemoryDumpManager is initialized in a slave process.
+  //  delegate: inversion-of-control interface for embedder-specific behaviors
+  //      (multiprocess handshaking). See the lifetime and thread-safety
+  //      requirements in the |MemoryDumpManagerDelegate| docstring.
+  void Initialize(MemoryDumpManagerDelegate* delegate, bool is_coordinator);
 
   // MemoryDumpManager does NOT take memory ownership of |mdp|, which is
   // expected to either be a singleton or unregister itself.
@@ -60,18 +67,17 @@
 
   // Requests a memory dump. The dump might happen or not depending on the
   // filters and categories specified when enabling tracing.
-  // The |dump_args| is used to specify the dump's level of detail.
   // The optional |callback| is executed asynchronously, on an arbitrary thread,
   // to notify about the completion of the global dump (i.e. after all the
   // processes have dumped) and its success (true iff all the dumps were
   // successful).
   void RequestGlobalDump(MemoryDumpType dump_type,
-                         const MemoryDumpArgs& dump_args,
+                         MemoryDumpLevelOfDetail level_of_detail,
                          const MemoryDumpCallback& callback);
 
   // Same as above (still asynchronous), but without callback.
   void RequestGlobalDump(MemoryDumpType dump_type,
-                         const MemoryDumpArgs& dump_args);
+                         MemoryDumpLevelOfDetail level_of_detail);
 
   // TraceLog::EnabledStateObserver implementation.
   void OnTraceLogEnabled() override;
@@ -92,24 +98,17 @@
 
   // Returns the name for a the allocated_objects dump. Use this to declare
   // suballocator dumps from other dump providers.
-  // It should not return nullptr after the manager has been initialized.
+  // It will return nullptr if there is no dump provider for the system
+  // allocator registered (which is currently the case for Mac OS).
   const char* system_allocator_pool_name() const {
-    return system_allocator_pool_name_;
+    return kSystemAllocatorPoolName;
   };
 
-  // Tells the initialization phase to skip scheduling periodic memory dumps.
-  void DisablePeriodicDumpsForTesting() {
-    disable_periodic_dumps_for_testing_ = true;
-  }
-
  private:
   friend struct DefaultDeleter<MemoryDumpManager>;  // For the testing instance.
   friend struct DefaultSingletonTraits<MemoryDumpManager>;
   friend class MemoryDumpManagerDelegate;
   friend class MemoryDumpManagerTest;
-  FRIEND_TEST_ALL_PREFIXES(MemoryDumpManagerTest, DisableFailingDumpers);
-  FRIEND_TEST_ALL_PREFIXES(MemoryDumpManagerTest,
-                           UnregisterDumperFromThreadWhileDumping);
 
   // Descriptor struct used to hold information about registered MDPs. It is
   // deliberately copyable, in order to allow it to be used as std::set value.
@@ -174,6 +173,7 @@
   };
 
   static const int kMaxConsecutiveFailuresCount;
+  static const char* const kSystemAllocatorPoolName;
 
   MemoryDumpManager();
   ~MemoryDumpManager() override;
@@ -206,6 +206,9 @@
 
   MemoryDumpManagerDelegate* delegate_;  // Not owned.
 
+  // When true, this instance is in charge of coordinating periodic dumps.
+  bool is_coordinator_;
+
   // Protects from concurrent accesses to the |dump_providers_*| and |delegate_|
   // to guard against disabling logging while dumping on another thread.
   Lock lock_;
@@ -221,17 +224,9 @@
   // expected to be valid only when tracing is enabled.
   uint64 tracing_process_id_;
 
-  // Name of the allocated_objects dump.
-  const char* system_allocator_pool_name_;
-
   // Skips the auto-registration of the core dumpers during Initialize().
   bool skip_core_dumpers_auto_registration_for_testing_;
 
-  // When true, the initialization phase does not start the periodic memory
-  // dumps.
-  // TODO(primiano): This should go into TraceConfig. https://goo.gl/5Hj3o0.
-  bool disable_periodic_dumps_for_testing_;
-
   DISALLOW_COPY_AND_ASSIGN(MemoryDumpManager);
 };
 
@@ -242,10 +237,6 @@
   virtual void RequestGlobalMemoryDump(const MemoryDumpRequestArgs& args,
                                        const MemoryDumpCallback& callback) = 0;
 
-  // Determines whether the MemoryDumpManager instance should be the master
-  // (the ones which initiates and coordinates the multiprocess dumps) or not.
-  virtual bool IsCoordinatorProcess() const = 0;
-
   // Returns tracing process id of the current process. This is used by
   // MemoryDumpManager::GetTracingProcessId.
   virtual uint64 GetTracingProcessId() const = 0;
diff --git a/trace_event/memory_dump_manager_unittest.cc b/trace_event/memory_dump_manager_unittest.cc
index 6200c2d..f409a4c 100644
--- a/trace_event/memory_dump_manager_unittest.cc
+++ b/trace_event/memory_dump_manager_unittest.cc
@@ -8,15 +8,18 @@
 #include "base/memory/scoped_vector.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
 #include "base/test/test_io_thread.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_config_memory_test_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using testing::_;
+using testing::AnyNumber;
 using testing::AtMost;
 using testing::Between;
 using testing::Invoke;
@@ -24,34 +27,40 @@
 
 namespace base {
 namespace trace_event {
-namespace {
-MemoryDumpArgs g_high_detail_args = {MemoryDumpArgs::LevelOfDetail::HIGH};
-MemoryDumpArgs g_low_detail_args = {MemoryDumpArgs::LevelOfDetail::LOW};
+
+// GTest matchers for MemoryDumpRequestArgs arguments.
+MATCHER(IsDetailedDump, "") {
+  return arg.level_of_detail == MemoryDumpLevelOfDetail::DETAILED;
 }
 
-// Testing MemoryDumpManagerDelegate which short-circuits dump requests locally
-// instead of performing IPC dances.
+MATCHER(IsLightDump, "") {
+  return arg.level_of_detail == MemoryDumpLevelOfDetail::LIGHT;
+}
+
+// Testing MemoryDumpManagerDelegate which, by default, short-circuits dump
+// requests locally to the MemoryDumpManager instead of performing IPC dances.
 class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate {
  public:
-  void RequestGlobalMemoryDump(const MemoryDumpRequestArgs& args,
-                               const MemoryDumpCallback& callback) override {
-    CreateProcessDump(args, callback);
+  MemoryDumpManagerDelegateForTesting() {
+    ON_CALL(*this, RequestGlobalMemoryDump(_, _))
+        .WillByDefault(Invoke(
+            this, &MemoryDumpManagerDelegateForTesting::CreateProcessDump));
   }
 
-  bool IsCoordinatorProcess() const override { return false; }
-  uint64 GetTracingProcessId() const override {
-    return MemoryDumpManager::kInvalidTracingProcessId;
-  }
-};
-
-class MemoryDumpManagerDelegateForPeriodicDumpTest
-    : public MemoryDumpManagerDelegateForTesting {
- public:
   MOCK_METHOD2(RequestGlobalMemoryDump,
                void(const MemoryDumpRequestArgs& args,
                     const MemoryDumpCallback& callback));
 
-  virtual bool IsCoordinatorProcess() const { return true; }
+  uint64 GetTracingProcessId() const {
+    NOTREACHED();
+    return MemoryDumpManager::kInvalidTracingProcessId;
+  }
+};
+
+class MockMemoryDumpProvider : public MemoryDumpProvider {
+ public:
+  MOCK_METHOD2(OnMemoryDump,
+               bool(const MemoryDumpArgs& args, ProcessMemoryDump* pmd));
 };
 
 class MemoryDumpManagerTest : public testing::Test {
@@ -62,12 +71,13 @@
     mdm_.reset(new MemoryDumpManager());
     MemoryDumpManager::SetInstanceForTesting(mdm_.get());
     ASSERT_EQ(mdm_, MemoryDumpManager::GetInstance());
-    MemoryDumpManager::GetInstance()->Initialize();
+    delegate_.reset(new MemoryDumpManagerDelegateForTesting);
   }
 
   void TearDown() override {
     MemoryDumpManager::SetInstanceForTesting(nullptr);
     mdm_.reset();
+    delegate_.reset();
     message_loop_.reset();
     TraceLog::DeleteForTesting();
   }
@@ -81,32 +91,33 @@
   }
 
  protected:
-  void SetDelegate(scoped_ptr<MemoryDumpManagerDelegateForTesting> delegate) {
-    delegate_ = delegate.Pass();
-    MemoryDumpManager::GetInstance()->SetDelegate(delegate_.get());
+  void InitializeMemoryDumpManager(bool is_coordinator) {
+    mdm_->Initialize(delegate_.get(), is_coordinator);
   }
 
-  // This enalbes tracing using the legacy category filter string.
-  void EnableTracing(const char* category) {
-    if (!delegate_) {
-      delegate_.reset(new MemoryDumpManagerDelegateForTesting());
-      MemoryDumpManager::GetInstance()->SetDelegate(delegate_.get());
-    }
-    TraceLog::GetInstance()->SetEnabled(
-        TraceConfig(category, ""), TraceLog::RECORDING_MODE);
+  void EnableTracingWithLegacyCategories(const char* category) {
+    TraceLog::GetInstance()->SetEnabled(TraceConfig(category, ""),
+                                        TraceLog::RECORDING_MODE);
   }
 
-  void EnableTracingWithTraceConfig(const char* trace_config) {
-    DCHECK(delegate_);
-    TraceConfig tc(trace_config);
-    TraceLog::GetInstance()->SetEnabled(tc, TraceLog::RECORDING_MODE);
+  void EnableTracingWithTraceConfig(const std::string& trace_config) {
+    TraceLog::GetInstance()->SetEnabled(TraceConfig(trace_config),
+                                        TraceLog::RECORDING_MODE);
   }
 
   void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }
 
+  bool IsPeriodicDumpingEnabled() const {
+    return mdm_->periodic_dump_timer_.IsRunning();
+  }
+
+  int GetMaxConsecutiveFailuresCount() const {
+    return MemoryDumpManager::kMaxConsecutiveFailuresCount;
+  }
+
   scoped_ptr<MemoryDumpManager> mdm_;
-  bool last_callback_success_;
   scoped_ptr<MemoryDumpManagerDelegateForTesting> delegate_;
+  bool last_callback_success_;
 
  private:
   scoped_ptr<MessageLoop> message_loop_;
@@ -115,220 +126,166 @@
   ShadowingAtExitManager at_exit_manager_;
 };
 
-class MockDumpProvider : public MemoryDumpProvider {
- public:
-  MockDumpProvider()
-      : dump_provider_to_register_or_unregister(nullptr),
-        last_session_state_(nullptr),
-        level_of_detail_(MemoryDumpArgs::LevelOfDetail::HIGH) {}
-
-  // Ctor used by the RespectTaskRunnerAffinity test.
-  explicit MockDumpProvider(
-      const scoped_refptr<SingleThreadTaskRunner>& task_runner)
-      : last_session_state_(nullptr),
-        task_runner_(task_runner),
-        level_of_detail_(MemoryDumpArgs::LevelOfDetail::HIGH) {}
-
-  // Ctor used by CheckMemoryDumpArgs test.
-  explicit MockDumpProvider(const MemoryDumpArgs::LevelOfDetail level_of_detail)
-      : last_session_state_(nullptr), level_of_detail_(level_of_detail) {}
-
-  virtual ~MockDumpProvider() {}
-
-  MOCK_METHOD2(OnMemoryDump,
-               bool(const MemoryDumpArgs& args, ProcessMemoryDump* pmd));
-
-  // OnMemoryDump() override for the RespectTaskRunnerAffinity test.
-  bool OnMemoryDump_CheckTaskRunner(const MemoryDumpArgs& args,
-                                    ProcessMemoryDump* pmd) {
-    EXPECT_TRUE(task_runner_->RunsTasksOnCurrentThread());
-    return true;
-  }
-
-  // OnMemoryDump() override for the SharedSessionState test.
-  bool OnMemoryDump_CheckSessionState(const MemoryDumpArgs& args,
-                                      ProcessMemoryDump* pmd) {
-    MemoryDumpSessionState* cur_session_state = pmd->session_state().get();
-    if (last_session_state_)
-      EXPECT_EQ(last_session_state_, cur_session_state);
-    last_session_state_ = cur_session_state;
-    return true;
-  }
-
-  // OnMemoryDump() override for the RegisterDumperWhileDumping test.
-  bool OnMemoryDump_RegisterExtraDumpProvider(const MemoryDumpArgs& args,
-                                              ProcessMemoryDump* pmd) {
-    MemoryDumpManager::GetInstance()->RegisterDumpProvider(
-        dump_provider_to_register_or_unregister);
-    return true;
-  }
-
-  // OnMemoryDump() override for the UnegisterDumperWhileDumping test.
-  bool OnMemoryDump_UnregisterDumpProvider(const MemoryDumpArgs& args,
-                                           ProcessMemoryDump* pmd) {
-    MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
-        dump_provider_to_register_or_unregister);
-    return true;
-  }
-
-  // OnMemoryDump() override for the CheckMemoryDumpArgs test.
-  bool OnMemoryDump_CheckMemoryDumpArgs(const MemoryDumpArgs& args,
-                                        ProcessMemoryDump* pmd) {
-    EXPECT_EQ(level_of_detail_, args.level_of_detail);
-    return true;
-  }
-
-  // Used by OnMemoryDump_(Un)RegisterExtraDumpProvider.
-  MemoryDumpProvider* dump_provider_to_register_or_unregister;
-
- private:
-  MemoryDumpSessionState* last_session_state_;
-  scoped_refptr<SingleThreadTaskRunner> task_runner_;
-  const MemoryDumpArgs::LevelOfDetail level_of_detail_;
-};
-
+// Basic sanity checks. Registers a memory dump provider and checks that it is
+// called, but only when memory-infra is enabled.
 TEST_F(MemoryDumpManagerTest, SingleDumper) {
-  MockDumpProvider mdp;
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp;
   mdm_->RegisterDumpProvider(&mdp);
 
   // Check that the dumper is not called if the memory category is not enabled.
-  EnableTracing("foo-and-bar-but-not-memory");
+  EnableTracingWithLegacyCategories("foobar-but-not-memory");
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
   EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
   mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                          g_high_detail_args);
+                          MemoryDumpLevelOfDetail::DETAILED);
   DisableTracing();
 
   // Now repeat enabling the memory category and check that the dumper is
   // invoked this time.
-  EnableTracing(MemoryDumpManager::kTraceCategory);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(3);
   EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3).WillRepeatedly(Return(true));
   for (int i = 0; i < 3; ++i)
     mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                            g_high_detail_args);
+                            MemoryDumpLevelOfDetail::DETAILED);
   DisableTracing();
 
   mdm_->UnregisterDumpProvider(&mdp);
 
-  // Finally check the unregister logic (no calls to the mdp after unregister).
-  EnableTracing(MemoryDumpManager::kTraceCategory);
+  // Finally check the unregister logic: the delegate will be invoked but not
+  // the dump provider, as it has been unregistered.
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
   EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
   mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                          g_high_detail_args);
+                          MemoryDumpLevelOfDetail::DETAILED);
   TraceLog::GetInstance()->SetDisabled();
 }
 
+// Checks that requesting dumps with high level of detail actually propagates
+// the level of the detail properly to OnMemoryDump() call on dump providers.
 TEST_F(MemoryDumpManagerTest, CheckMemoryDumpArgs) {
-  // Check that requesting dumps with high level of detail actually propagates
-  // to OnMemoryDump() call on dump providers.
-  MockDumpProvider mdp_high_detail(MemoryDumpArgs::LevelOfDetail::HIGH);
-  mdm_->RegisterDumpProvider(&mdp_high_detail);
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp;
 
-  EnableTracing(MemoryDumpManager::kTraceCategory);
-  EXPECT_CALL(mdp_high_detail, OnMemoryDump(_, _))
-      .Times(1)
-      .WillRepeatedly(
-          Invoke(&mdp_high_detail,
-                 &MockDumpProvider::OnMemoryDump_CheckMemoryDumpArgs));
+  mdm_->RegisterDumpProvider(&mdp);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp, OnMemoryDump(IsDetailedDump(), _)).WillOnce(Return(true));
   mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                          g_high_detail_args);
+                          MemoryDumpLevelOfDetail::DETAILED);
   DisableTracing();
-  mdm_->UnregisterDumpProvider(&mdp_high_detail);
+  mdm_->UnregisterDumpProvider(&mdp);
 
   // Check that requesting dumps with low level of detail actually propagates to
   // OnMemoryDump() call on dump providers.
-  MockDumpProvider mdp_low_detail(MemoryDumpArgs::LevelOfDetail::LOW);
-  mdm_->RegisterDumpProvider(&mdp_low_detail);
-
-  EnableTracing(MemoryDumpManager::kTraceCategory);
-  EXPECT_CALL(mdp_low_detail, OnMemoryDump(_, _))
-      .Times(1)
-      .WillRepeatedly(
-          Invoke(&mdp_low_detail,
-                 &MockDumpProvider::OnMemoryDump_CheckMemoryDumpArgs));
+  mdm_->RegisterDumpProvider(&mdp);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp, OnMemoryDump(IsLightDump(), _)).WillOnce(Return(true));
   mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                          g_low_detail_args);
+                          MemoryDumpLevelOfDetail::LIGHT);
   DisableTracing();
-  mdm_->UnregisterDumpProvider(&mdp_low_detail);
+  mdm_->UnregisterDumpProvider(&mdp);
 }
 
+// Checks that the SharedSessionState object is acqually shared over time.
 TEST_F(MemoryDumpManagerTest, SharedSessionState) {
-  MockDumpProvider mdp1;
-  MockDumpProvider mdp2;
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp1;
+  MockMemoryDumpProvider mdp2;
   mdm_->RegisterDumpProvider(&mdp1);
   mdm_->RegisterDumpProvider(&mdp2);
 
-  EnableTracing(MemoryDumpManager::kTraceCategory);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  const MemoryDumpSessionState* session_state = mdm_->session_state().get();
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(2);
   EXPECT_CALL(mdp1, OnMemoryDump(_, _))
       .Times(2)
-      .WillRepeatedly(
-          Invoke(&mdp1, &MockDumpProvider::OnMemoryDump_CheckSessionState));
+      .WillRepeatedly(Invoke([session_state](const MemoryDumpArgs&,
+                                             ProcessMemoryDump* pmd) -> bool {
+        EXPECT_EQ(session_state, pmd->session_state().get());
+        return true;
+      }));
   EXPECT_CALL(mdp2, OnMemoryDump(_, _))
       .Times(2)
-      .WillRepeatedly(
-          Invoke(&mdp2, &MockDumpProvider::OnMemoryDump_CheckSessionState));
+      .WillRepeatedly(Invoke([session_state](const MemoryDumpArgs&,
+                                             ProcessMemoryDump* pmd) -> bool {
+        EXPECT_EQ(session_state, pmd->session_state().get());
+        return true;
+      }));
 
   for (int i = 0; i < 2; ++i)
     mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                            g_high_detail_args);
+                            MemoryDumpLevelOfDetail::DETAILED);
 
   DisableTracing();
 }
 
+// Checks that the (Un)RegisterDumpProvider logic behaves sanely.
 TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
-  MockDumpProvider mdp1;
-  MockDumpProvider mdp2;
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp1;
+  MockMemoryDumpProvider mdp2;
 
   // Enable only mdp1.
   mdm_->RegisterDumpProvider(&mdp1);
-  EnableTracing(MemoryDumpManager::kTraceCategory);
-  EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true));
   EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(0);
   mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                          g_high_detail_args);
+                          MemoryDumpLevelOfDetail::DETAILED);
   DisableTracing();
 
   // Invert: enable mdp1 and disable mdp2.
   mdm_->UnregisterDumpProvider(&mdp1);
   mdm_->RegisterDumpProvider(&mdp2);
-  EnableTracing(MemoryDumpManager::kTraceCategory);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
   EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
-  EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _)).WillOnce(Return(true));
   mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                          g_high_detail_args);
+                          MemoryDumpLevelOfDetail::DETAILED);
   DisableTracing();
 
   // Enable both mdp1 and mdp2.
   mdm_->RegisterDumpProvider(&mdp1);
-  EnableTracing(MemoryDumpManager::kTraceCategory);
-  EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
-  EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true));
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _)).WillOnce(Return(true));
   mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                          g_high_detail_args);
+                          MemoryDumpLevelOfDetail::DETAILED);
   DisableTracing();
 }
 
-// Verify that whether OnMemoryDump is called depends only on the current
+// Checks that the dump provider invocations depend only on the current
 // registration state and not on previous registrations and dumps.
 TEST_F(MemoryDumpManagerTest, RegistrationConsistency) {
-  MockDumpProvider mdp;
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp;
 
   mdm_->RegisterDumpProvider(&mdp);
 
   {
-    EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1);
-    EnableTracing(MemoryDumpManager::kTraceCategory);
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+    EXPECT_CALL(mdp, OnMemoryDump(_, _)).WillOnce(Return(true));
+    EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
     mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                            g_high_detail_args);
+                            MemoryDumpLevelOfDetail::DETAILED);
     DisableTracing();
   }
 
   mdm_->UnregisterDumpProvider(&mdp);
 
   {
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
     EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
-    EnableTracing(MemoryDumpManager::kTraceCategory);
+    EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
     mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                            g_high_detail_args);
+                            MemoryDumpLevelOfDetail::DETAILED);
     DisableTracing();
   }
 
@@ -336,10 +293,11 @@
   mdm_->UnregisterDumpProvider(&mdp);
 
   {
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
     EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
-    EnableTracing(MemoryDumpManager::kTraceCategory);
+    EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
     mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                            g_high_detail_args);
+                            MemoryDumpLevelOfDetail::DETAILED);
     DisableTracing();
   }
 
@@ -348,10 +306,11 @@
   mdm_->RegisterDumpProvider(&mdp);
 
   {
-    EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1);
-    EnableTracing(MemoryDumpManager::kTraceCategory);
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+    EXPECT_CALL(mdp, OnMemoryDump(_, _)).WillOnce(Return(true));
+    EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
     mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                            g_high_detail_args);
+                            MemoryDumpLevelOfDetail::DETAILED);
     DisableTracing();
   }
 }
@@ -361,27 +320,33 @@
 // threads and registering a MemoryDumpProvider on each of them. At each
 // iteration, one thread is removed, to check the live unregistration logic.
 TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
   const uint32 kNumInitialThreads = 8;
 
   ScopedVector<Thread> threads;
-  ScopedVector<MockDumpProvider> mdps;
+  ScopedVector<MockMemoryDumpProvider> mdps;
 
   // Create the threads and setup the expectations. Given that at each iteration
   // we will pop out one thread/MemoryDumpProvider, each MDP is supposed to be
   // invoked a number of times equal to its index.
   for (uint32 i = kNumInitialThreads; i > 0; --i) {
-    threads.push_back(new Thread("test thread"));
+    Thread* thread = new Thread("test thread");
+    threads.push_back(thread);
     threads.back()->Start();
-    mdps.push_back(new MockDumpProvider(threads.back()->task_runner()));
-    MockDumpProvider* mdp = mdps.back();
-    mdm_->RegisterDumpProvider(mdp, threads.back()->task_runner());
+    scoped_refptr<SingleThreadTaskRunner> task_runner = thread->task_runner();
+    MockMemoryDumpProvider* mdp = new MockMemoryDumpProvider();
+    mdps.push_back(mdp);
+    mdm_->RegisterDumpProvider(mdp, task_runner);
     EXPECT_CALL(*mdp, OnMemoryDump(_, _))
         .Times(i)
-        .WillRepeatedly(
-            Invoke(mdp, &MockDumpProvider::OnMemoryDump_CheckTaskRunner));
+        .WillRepeatedly(Invoke(
+            [task_runner](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
+              EXPECT_TRUE(task_runner->RunsTasksOnCurrentThread());
+              return true;
+            }));
   }
 
-  EnableTracing(MemoryDumpManager::kTraceCategory);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
 
   while (!threads.empty()) {
     last_callback_success_ = false;
@@ -390,10 +355,11 @@
       MemoryDumpCallback callback =
           Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
                MessageLoop::current()->task_runner(), run_loop.QuitClosure());
+      EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
       mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                              g_high_detail_args, callback);
-      // This nested message loop (|run_loop|) will be quit if and only if
-      // the RequestGlobalDump callback is invoked.
+                              MemoryDumpLevelOfDetail::DETAILED, callback);
+      // This nested message loop (|run_loop|) will quit if and only if the
+      // |callback| passed to RequestGlobalDump() is invoked.
       run_loop.Run();
     }
     EXPECT_TRUE(last_callback_success_);
@@ -418,48 +384,60 @@
   DisableTracing();
 }
 
-// Enable both dump providers, make sure that mdp gets disabled after 3 failures
-// and not disabled after 1.
+// Checks that providers get disabled after 3 consecutive failures, but not
+// otherwise (e.g., if interleaved).
 TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) {
-  MockDumpProvider mdp1;
-  MockDumpProvider mdp2;
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp1;
+  MockMemoryDumpProvider mdp2;
 
   mdm_->RegisterDumpProvider(&mdp1);
   mdm_->RegisterDumpProvider(&mdp2);
-  EnableTracing(MemoryDumpManager::kTraceCategory);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+
+  const int kNumDumps = 2 * GetMaxConsecutiveFailuresCount();
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(kNumDumps);
 
   EXPECT_CALL(mdp1, OnMemoryDump(_, _))
-      .Times(MemoryDumpManager::kMaxConsecutiveFailuresCount)
+      .Times(GetMaxConsecutiveFailuresCount())
       .WillRepeatedly(Return(false));
 
   EXPECT_CALL(mdp2, OnMemoryDump(_, _))
-      .Times(1 + MemoryDumpManager::kMaxConsecutiveFailuresCount)
       .WillOnce(Return(false))
-      .WillRepeatedly(Return(true));
-  for (int i = 0; i < 1 + MemoryDumpManager::kMaxConsecutiveFailuresCount;
-       i++) {
+      .WillOnce(Return(true))
+      .WillOnce(Return(false))
+      .WillOnce(Return(false))
+      .WillOnce(Return(true))
+      .WillOnce(Return(false));
+
+  for (int i = 0; i < kNumDumps; i++) {
     mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                            g_high_detail_args);
+                            MemoryDumpLevelOfDetail::DETAILED);
   }
 
   DisableTracing();
 }
 
-// Sneakily register an extra memory dump provider while an existing one is
+// Sneakily registers an extra memory dump provider while an existing one is
 // dumping and expect it to take part in the already active tracing session.
 TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) {
-  MockDumpProvider mdp1;
-  MockDumpProvider mdp2;
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp1;
+  MockMemoryDumpProvider mdp2;
 
-  mdp1.dump_provider_to_register_or_unregister = &mdp2;
   mdm_->RegisterDumpProvider(&mdp1);
-  EnableTracing(MemoryDumpManager::kTraceCategory);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(4);
 
   EXPECT_CALL(mdp1, OnMemoryDump(_, _))
       .Times(4)
       .WillOnce(Return(true))
-      .WillOnce(Invoke(
-          &mdp1, &MockDumpProvider::OnMemoryDump_RegisterExtraDumpProvider))
+      .WillOnce(
+          Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
+            MemoryDumpManager::GetInstance()->RegisterDumpProvider(&mdp2);
+            return true;
+          }))
       .WillRepeatedly(Return(true));
 
   // Depending on the insertion order (before or after mdp1), mdp2 might be
@@ -470,52 +448,58 @@
 
   for (int i = 0; i < 4; i++) {
     mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                            g_high_detail_args);
+                            MemoryDumpLevelOfDetail::DETAILED);
   }
 
   DisableTracing();
 }
 
-// Like the above, but suddenly unregister the dump provider.
+// Like RegisterDumperWhileDumping, but unregister the dump provider instead.
 TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileDumping) {
-  MockDumpProvider mdp1;
-  MockDumpProvider mdp2;
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp1;
+  MockMemoryDumpProvider mdp2;
 
   mdm_->RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get());
   mdm_->RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get());
-  mdp1.dump_provider_to_register_or_unregister = &mdp2;
-  EnableTracing(MemoryDumpManager::kTraceCategory);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(4);
 
   EXPECT_CALL(mdp1, OnMemoryDump(_, _))
       .Times(4)
       .WillOnce(Return(true))
       .WillOnce(
-          Invoke(&mdp1, &MockDumpProvider::OnMemoryDump_UnregisterDumpProvider))
+          Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
+            MemoryDumpManager::GetInstance()->UnregisterDumpProvider(&mdp2);
+            return true;
+          }))
       .WillRepeatedly(Return(true));
 
   // Depending on the insertion order (before or after mdp1), mdp2 might have
-  // been already called when OnMemoryDump_UnregisterDumpProvider happens.
+  // been already called when UnregisterDumpProvider happens.
   EXPECT_CALL(mdp2, OnMemoryDump(_, _))
       .Times(Between(1, 2))
       .WillRepeatedly(Return(true));
 
   for (int i = 0; i < 4; i++) {
     mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                            g_high_detail_args);
+                            MemoryDumpLevelOfDetail::DETAILED);
   }
 
   DisableTracing();
 }
 
-// Verify that the dump does not abort when unregistering a provider while
+// Checks that the dump does not abort when unregistering a provider while
 // dumping from a different thread than the dumping thread.
 TEST_F(MemoryDumpManagerTest, UnregisterDumperFromThreadWhileDumping) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
   ScopedVector<TestIOThread> threads;
-  ScopedVector<MockDumpProvider> mdps;
+  ScopedVector<MockMemoryDumpProvider> mdps;
 
   for (int i = 0; i < 2; i++) {
     threads.push_back(new TestIOThread(TestIOThread::kAutoStart));
-    mdps.push_back(new MockDumpProvider(threads.back()->task_runner()));
+    mdps.push_back(new MockMemoryDumpProvider());
     mdm_->RegisterDumpProvider(mdps.back(), threads.back()->task_runner());
   }
 
@@ -524,10 +508,10 @@
 
   // When OnMemoryDump is called on either of the dump providers, it will
   // unregister the other one.
-  for (MockDumpProvider* mdp : mdps) {
+  for (MockMemoryDumpProvider* mdp : mdps) {
     int other_idx = (mdps.front() == mdp);
     TestIOThread* other_thread = threads[other_idx];
-    MockDumpProvider* other_mdp = mdps[other_idx];
+    MockMemoryDumpProvider* other_mdp = mdps[other_idx];
     auto on_dump = [this, other_thread, other_mdp, &on_memory_dump_call_count](
         const MemoryDumpArgs& args, ProcessMemoryDump* pmd) {
       other_thread->PostTaskAndWait(
@@ -549,10 +533,11 @@
       Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
            MessageLoop::current()->task_runner(), run_loop.QuitClosure());
 
-  EnableTracing(MemoryDumpManager::kTraceCategory);
-  MemoryDumpRequestArgs request_args = {0, MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                        g_high_detail_args};
-  mdm_->CreateProcessDump(request_args, callback);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                          MemoryDumpLevelOfDetail::DETAILED, callback);
 
   run_loop.Run();
 
@@ -562,12 +547,14 @@
   DisableTracing();
 }
 
-// Ensures that a NACK callback is invoked if RequestGlobalDump is called when
+// Checks that a NACK callback is invoked if RequestGlobalDump() is called when
 // tracing is not enabled.
 TEST_F(MemoryDumpManagerTest, CallbackCalledOnFailure) {
-  MockDumpProvider mdp1;
-
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp1;
   mdm_->RegisterDumpProvider(&mdp1);
+
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
   EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
 
   last_callback_success_ = true;
@@ -577,64 +564,142 @@
         Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
              MessageLoop::current()->task_runner(), run_loop.QuitClosure());
     mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                            g_high_detail_args, callback);
+                            MemoryDumpLevelOfDetail::DETAILED, callback);
     run_loop.Run();
   }
   EXPECT_FALSE(last_callback_success_);
 }
 
-MATCHER(IsHighDetail, "") {
-  return arg.dump_args.level_of_detail == MemoryDumpArgs::LevelOfDetail::HIGH;
+// Checks that is the MemoryDumpManager is initialized after tracing already
+// began, it will still late-join the party (real use case: startup tracing).
+TEST_F(MemoryDumpManagerTest, InitializedAfterStartOfTracing) {
+  MockMemoryDumpProvider mdp;
+  mdm_->RegisterDumpProvider(&mdp);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+
+  // First check that a RequestGlobalDump() issued before the MemoryDumpManager
+  // initialization gets NACK-ed cleanly.
+  {
+    EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
+    RunLoop run_loop;
+    MemoryDumpCallback callback =
+        Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
+             MessageLoop::current()->task_runner(), run_loop.QuitClosure());
+    mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                            MemoryDumpLevelOfDetail::DETAILED, callback);
+    run_loop.Run();
+    EXPECT_FALSE(last_callback_success_);
+  }
+
+  // Now late-initialize the MemoryDumpManager and check that the
+  // RequestGlobalDump completes successfully.
+  {
+    EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1);
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+    InitializeMemoryDumpManager(false /* is_coordinator */);
+    RunLoop run_loop;
+    MemoryDumpCallback callback =
+        Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
+             MessageLoop::current()->task_runner(), run_loop.QuitClosure());
+    mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                            MemoryDumpLevelOfDetail::DETAILED, callback);
+    run_loop.Run();
+    EXPECT_TRUE(last_callback_success_);
+  }
+  DisableTracing();
 }
 
-MATCHER(IsLowDetail, "") {
-  return arg.dump_args.level_of_detail == MemoryDumpArgs::LevelOfDetail::LOW;
+// This test (and the MemoryDumpManagerTestCoordinator below) crystallizes the
+// expectations of the chrome://tracing UI and chrome telemetry w.r.t. periodic
+// dumps in memory-infra, handling gracefully the transition between the legacy
+// and the new-style (JSON-based) TraceConfig.
+TEST_F(MemoryDumpManagerTest, TraceConfigExpectations) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MemoryDumpManagerDelegateForTesting& delegate = *delegate_;
+
+  // Don't trigger the default behavior of the mock delegate in this test,
+  // which would short-circuit the dump request to the actual
+  // CreateProcessDump().
+  // We don't want to create any dump in this test, only check whether the dumps
+  // are requested or not.
+  ON_CALL(delegate, RequestGlobalMemoryDump(_, _)).WillByDefault(Return());
+
+  // Enabling memory-infra in a non-coordinator process should not trigger any
+  // periodic dumps.
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_FALSE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+
+  // Enabling memory-infra with the new (JSON) TraceConfig in a non-coordinator
+  // process with a fully defined trigger config should NOT enable any periodic
+  // dumps.
+  EnableTracingWithTraceConfig(
+      TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(1, 5));
+  EXPECT_FALSE(IsPeriodicDumpingEnabled());
+  DisableTracing();
 }
 
-TEST_F(MemoryDumpManagerTest, SchedulePeriodicDumpsFromTraceConfig) {
-  const char kMemoryDumpTraceConfigString[] =
-      "{"
-      "\"included_categories\":["
-      "\"disabled-by-default-memory-infra\""
-      "],"
-      "\"memory_dump_config\":{"
-      "\"triggers\":["
-      "{"
-      "\"mode\":\"light\","
-      "\"periodic_interval_ms\":1"
-      "},"
-      "{"
-      "\"mode\":\"detailed\","
-      "\"periodic_interval_ms\":3"
-      "}"
-      "]"
-      "}"
-      "}";
+TEST_F(MemoryDumpManagerTest, TraceConfigExpectationsWhenIsCoordinator) {
+  InitializeMemoryDumpManager(true /* is_coordinator */);
+  MemoryDumpManagerDelegateForTesting& delegate = *delegate_;
+  ON_CALL(delegate, RequestGlobalMemoryDump(_, _)).WillByDefault(Return());
 
+  // Enabling memory-infra with the legacy TraceConfig (category filter) in
+  // a coordinator process should enable periodic dumps.
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_TRUE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+
+  // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
+  // process without specifying any "memory_dump_config" section should enable
+  // periodic dumps. This is to preserve the behavior chrome://tracing UI, that
+  // is: ticking memory-infra should dump periodically with the default config.
+  EnableTracingWithTraceConfig(
+      TraceConfigMemoryTestUtil::GetTraceConfig_NoTriggers());
+  EXPECT_TRUE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+
+  // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
+  // process with an empty "memory_dump_config" should NOT enable periodic
+  // dumps. This is the way telemetry is supposed to use memory-infra with
+  // only explicitly triggered dumps.
+  EnableTracingWithTraceConfig(
+      TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers());
+  EXPECT_FALSE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+
+  // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
+  // process with a fully defined trigger config should cause periodic dumps to
+  // be performed in the correct order.
   RunLoop run_loop;
-  scoped_ptr<MemoryDumpManagerDelegateForPeriodicDumpTest> delegate(
-      new MemoryDumpManagerDelegateForPeriodicDumpTest());
-
   auto quit_closure = run_loop.QuitClosure();
+
+  const int kHeavyDumpRate = 5;
+  const int kLightDumpPeriodMs = 1;
+  const int kHeavyDumpPeriodMs = kHeavyDumpRate * kLightDumpPeriodMs;
+  // The expected sequence with light=1ms, heavy=5ms is H,L,L,L,L,H,...
   testing::InSequence sequence;
-  EXPECT_CALL(*delegate.get(), RequestGlobalMemoryDump(IsHighDetail(), _))
-      .Times(1);
-  EXPECT_CALL(*delegate.get(), RequestGlobalMemoryDump(IsLowDetail(), _))
-      .Times(2);
-  EXPECT_CALL(*delegate.get(), RequestGlobalMemoryDump(IsHighDetail(), _))
-      .Times(1);
-  EXPECT_CALL(*delegate.get(), RequestGlobalMemoryDump(IsLowDetail(), _))
-      .Times(1)
+  EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsDetailedDump(), _));
+  EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _))
+      .Times(kHeavyDumpRate - 1);
+  EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsDetailedDump(), _));
+  EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _))
+      .Times(kHeavyDumpRate - 2);
+  EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _))
       .WillOnce(Invoke([quit_closure](const MemoryDumpRequestArgs& args,
                                       const MemoryDumpCallback& callback) {
-        TraceLog::GetInstance()->SetDisabled();
         ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure);
       }));
 
-  SetDelegate(delegate.Pass());
-  EnableTracingWithTraceConfig(kMemoryDumpTraceConfigString);
+  // Swallow all the final spurious calls until tracing gets disabled.
+  EXPECT_CALL(delegate, RequestGlobalMemoryDump(_, _)).Times(AnyNumber());
 
+  EnableTracingWithTraceConfig(
+      TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(
+          kLightDumpPeriodMs, kHeavyDumpPeriodMs));
   run_loop.Run();
+  DisableTracing();
 }
 
 }  // namespace trace_event
diff --git a/trace_event/memory_dump_provider.h b/trace_event/memory_dump_provider.h
index 6ab20aa..3b1f136 100644
--- a/trace_event/memory_dump_provider.h
+++ b/trace_event/memory_dump_provider.h
@@ -7,23 +7,17 @@
 
 #include "base/base_export.h"
 #include "base/macros.h"
+#include "base/trace_event/memory_dump_request_args.h"
 
 namespace base {
 namespace trace_event {
 
 class ProcessMemoryDump;
 
-// Contains information about the type of memory dump the MemoryDumpProvider
-// should generate on dump request. This is to control the size of dumps
-// generated.
+// Args passed to OnMemoryDump(). This is to avoid rewriting all the subclasses
+// in the codebase when extending the MemoryDumpProvider API.
 struct MemoryDumpArgs {
-  enum class LevelOfDetail {
-    LOW,
-    HIGH,
-    LAST = HIGH  // For IPC Macros.
-  };
-
-  LevelOfDetail level_of_detail;
+  MemoryDumpLevelOfDetail level_of_detail;
 };
 
 // The contract interface that memory dump providers must implement.
diff --git a/trace_event/memory_dump_request_args.cc b/trace_event/memory_dump_request_args.cc
index 79c2802..48b5ba6 100644
--- a/trace_event/memory_dump_request_args.cc
+++ b/trace_event/memory_dump_request_args.cc
@@ -13,16 +13,38 @@
 const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type) {
   switch (dump_type) {
     case MemoryDumpType::TASK_BEGIN:
-      return "TASK_BEGIN";
+      return "task_begin";
     case MemoryDumpType::TASK_END:
-      return "TASK_END";
+      return "task_end";
     case MemoryDumpType::PERIODIC_INTERVAL:
-      return "PERIODIC_INTERVAL";
+      return "periodic_interval";
     case MemoryDumpType::EXPLICITLY_TRIGGERED:
-      return "EXPLICITLY_TRIGGERED";
+      return "explicitly_triggered";
   }
   NOTREACHED();
-  return "UNKNOWN";
+  return "unknown";
+}
+
+const char* MemoryDumpLevelOfDetailToString(
+    const MemoryDumpLevelOfDetail& level_of_detail) {
+  switch (level_of_detail) {
+    case MemoryDumpLevelOfDetail::LIGHT:
+      return "light";
+    case MemoryDumpLevelOfDetail::DETAILED:
+      return "detailed";
+  }
+  NOTREACHED();
+  return "unknown";
+}
+
+MemoryDumpLevelOfDetail StringToMemoryDumpLevelOfDetail(
+    const std::string& str) {
+  if (str == "light")
+    return MemoryDumpLevelOfDetail::LIGHT;
+  if (str == "detailed")
+    return MemoryDumpLevelOfDetail::DETAILED;
+  NOTREACHED();
+  return MemoryDumpLevelOfDetail::LAST;
 }
 
 }  // namespace trace_event
diff --git a/trace_event/memory_dump_request_args.h b/trace_event/memory_dump_request_args.h
index 27ea451..ac38390 100644
--- a/trace_event/memory_dump_request_args.h
+++ b/trace_event/memory_dump_request_args.h
@@ -8,9 +8,10 @@
 // This file defines the types and structs used to issue memory dump requests.
 // These are also used in the IPCs for coordinating inter-process memory dumps.
 
+#include <string>
+
 #include "base/base_export.h"
 #include "base/callback.h"
-#include "base/trace_event/memory_dump_provider.h"
 
 namespace base {
 namespace trace_event {
@@ -25,11 +26,18 @@
   LAST = EXPLICITLY_TRIGGERED    // For IPC macros.
 };
 
-// Returns the name in string for the dump type given.
-BASE_EXPORT const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type);
+// Tells the MemoryDumpProvider(s) how much detailed their dumps should be.
+// MemoryDumpProvider instances must guarantee that level of detail does not
+// affect the total size reported in the root node, but only the granularity of
+// the child MemoryAllocatorDump(s).
+enum class MemoryDumpLevelOfDetail {
+  LIGHT,           // Few entries, typically a fixed number, per dump.
+  DETAILED,        // Unrestricted amount of entries per dump.
+  LAST = DETAILED  // For IPC Macros.
+};
 
-using MemoryDumpCallback = Callback<void(uint64 dump_guid, bool success)>;
-
+// Initial request arguments for a global memory dump. (see
+// MemoryDumpManager::RequestGlobalMemoryDump()).
 struct BASE_EXPORT MemoryDumpRequestArgs {
   // Globally unique identifier. In multi-process dumps, all processes issue a
   // local dump with the same guid. This allows the trace importers to
@@ -37,10 +45,19 @@
   uint64 dump_guid;
 
   MemoryDumpType dump_type;
-
-  MemoryDumpArgs dump_args;
+  MemoryDumpLevelOfDetail level_of_detail;
 };
 
+using MemoryDumpCallback = Callback<void(uint64 dump_guid, bool success)>;
+
+BASE_EXPORT const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type);
+
+BASE_EXPORT const char* MemoryDumpLevelOfDetailToString(
+    const MemoryDumpLevelOfDetail& level_of_detail);
+
+BASE_EXPORT MemoryDumpLevelOfDetail
+StringToMemoryDumpLevelOfDetail(const std::string& str);
+
 }  // namespace trace_event
 }  // namespace base
 
diff --git a/trace_event/process_memory_dump.h b/trace_event/process_memory_dump.h
index 3b71a2c..da18a14 100644
--- a/trace_event/process_memory_dump.h
+++ b/trace_event/process_memory_dump.h
@@ -25,12 +25,8 @@
 class MemoryDumpManager;
 class MemoryDumpSessionState;
 
-// ProcessMemoryDump is as a strongly typed container which enforces the data
-// model for each memory dump and holds the dumps produced by the
-// MemoryDumpProvider(s) for a specific process.
-// At trace generation time (i.e. when AsValue() is called), ProcessMemoryDump
-// will compose a key-value dictionary of the various dumps obtained at trace
-// dump point time.
+// ProcessMemoryDump is as a strongly typed container which holds the dumps
+// produced by the MemoryDumpProvider(s) for a specific process.
 class BASE_EXPORT ProcessMemoryDump {
  public:
   struct MemoryAllocatorDumpEdge {
diff --git a/trace_event/process_memory_maps_dump_provider.cc b/trace_event/process_memory_maps_dump_provider.cc
index 2dcdd37..38b2573 100644
--- a/trace_event/process_memory_maps_dump_provider.cc
+++ b/trace_event/process_memory_maps_dump_provider.cc
@@ -168,7 +168,7 @@
 bool ProcessMemoryMapsDumpProvider::OnMemoryDump(const MemoryDumpArgs& args,
                                                  ProcessMemoryDump* pmd) {
   // Snapshot of memory maps is not taken for light dump requests.
-  if (args.level_of_detail == MemoryDumpArgs::LevelOfDetail::LOW)
+  if (args.level_of_detail == MemoryDumpLevelOfDetail::LIGHT)
     return true;
 
   uint32 res = 0;
diff --git a/trace_event/process_memory_maps_dump_provider_unittest.cc b/trace_event/process_memory_maps_dump_provider_unittest.cc
index f951a09..a73a21c 100644
--- a/trace_event/process_memory_maps_dump_provider_unittest.cc
+++ b/trace_event/process_memory_maps_dump_provider_unittest.cc
@@ -110,7 +110,7 @@
   const uint32 kProtR = ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
   const uint32 kProtW = ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
   const uint32 kProtX = ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
-  const MemoryDumpArgs dump_args = {MemoryDumpArgs::LevelOfDetail::HIGH};
+  const MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
 
   auto pmmdp = ProcessMemoryMapsDumpProvider::GetInstance();
 
diff --git a/trace_event/process_memory_totals_dump_provider_unittest.cc b/trace_event/process_memory_totals_dump_provider_unittest.cc
index 015cb2d..4ec37f5 100644
--- a/trace_event/process_memory_totals_dump_provider_unittest.cc
+++ b/trace_event/process_memory_totals_dump_provider_unittest.cc
@@ -12,7 +12,7 @@
 namespace trace_event {
 
 TEST(ProcessMemoryTotalsDumpProviderTest, DumpRSS) {
-  const MemoryDumpArgs high_detail_args = {MemoryDumpArgs::LevelOfDetail::HIGH};
+  const MemoryDumpArgs high_detail_args = {MemoryDumpLevelOfDetail::DETAILED};
   auto pmtdp = ProcessMemoryTotalsDumpProvider::GetInstance();
   scoped_ptr<ProcessMemoryDump> pmd_before(new ProcessMemoryDump(nullptr));
   scoped_ptr<ProcessMemoryDump> pmd_after(new ProcessMemoryDump(nullptr));
diff --git a/trace_event/trace_config.cc b/trace_event/trace_config.cc
index 8f0f1c4..cf3f3a6 100644
--- a/trace_event/trace_config.cc
+++ b/trace_event/trace_config.cc
@@ -11,6 +11,7 @@
 #include "base/strings/string_tokenizer.h"
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_dump_request_args.h"
 #include "base/trace_event/trace_event.h"
 
 namespace base {
@@ -44,16 +45,14 @@
 const char kTriggersParam[] = "triggers";
 const char kPeriodicIntervalParam[] = "periodic_interval_ms";
 const char kModeParam[] = "mode";
-const char kDetailedParam[] = "detailed";
-const char kLightParam[] = "light";
 
 // Default configuration of memory dumps.
 const TraceConfig::MemoryDumpTriggerConfig kDefaultHeavyMemoryDumpTrigger = {
     2000,  // periodic_interval_ms
-    MemoryDumpArgs::LevelOfDetail::HIGH};
+    MemoryDumpLevelOfDetail::DETAILED};
 const TraceConfig::MemoryDumpTriggerConfig kDefaultLightMemoryDumpTrigger = {
     250,  // periodic_interval_ms
-    MemoryDumpArgs::LevelOfDetail::LOW};
+    MemoryDumpLevelOfDetail::LIGHT};
 
 }  // namespace
 
@@ -465,7 +464,6 @@
       continue;
 
     MemoryDumpTriggerConfig dump_config;
-    std::string dump_type;
     int interval = 0;
 
     if (!trigger->GetInteger(kPeriodicIntervalParam, &interval)) {
@@ -473,14 +471,10 @@
     }
     DCHECK_GT(interval, 0);
     dump_config.periodic_interval_ms = static_cast<uint32>(interval);
-    dump_config.level_of_detail = MemoryDumpArgs::LevelOfDetail::LOW;
-
-    if (trigger->GetString(kModeParam, &dump_type)) {
-      if (dump_type == kDetailedParam) {
-        dump_config.level_of_detail = MemoryDumpArgs::LevelOfDetail::HIGH;
-      }
-    }
-
+    std::string level_of_detail_str;
+    trigger->GetString(kModeParam, &level_of_detail_str);
+    dump_config.level_of_detail =
+        StringToMemoryDumpLevelOfDetail(level_of_detail_str);
     memory_dump_config_.push_back(dump_config);
   }
 }
@@ -541,17 +535,8 @@
           new base::DictionaryValue());
       trigger_dict->SetInteger(kPeriodicIntervalParam,
                                static_cast<int>(config.periodic_interval_ms));
-
-      switch (config.level_of_detail) {
-        case MemoryDumpArgs::LevelOfDetail::LOW:
-          trigger_dict->SetString(kModeParam, kLightParam);
-          break;
-        case MemoryDumpArgs::LevelOfDetail::HIGH:
-          trigger_dict->SetString(kModeParam, kDetailedParam);
-          break;
-        default:
-          NOTREACHED();
-      }
+      trigger_dict->SetString(
+          kModeParam, MemoryDumpLevelOfDetailToString(config.level_of_detail));
       triggers_list->Append(trigger_dict.Pass());
     }
 
diff --git a/trace_event/trace_config.h b/trace_event/trace_config.h
index 82ef9d7..44cf16d 100644
--- a/trace_event/trace_config.h
+++ b/trace_event/trace_config.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// 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.
 
@@ -10,7 +10,7 @@
 
 #include "base/base_export.h"
 #include "base/gtest_prod_util.h"
-#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/memory_dump_request_args.h"
 #include "base/values.h"
 
 namespace base {
@@ -40,7 +40,7 @@
   // "memory-infra" category is enabled.
   struct MemoryDumpTriggerConfig {
     uint32 periodic_interval_ms;
-    MemoryDumpArgs::LevelOfDetail level_of_detail;
+    MemoryDumpLevelOfDetail level_of_detail;
   };
 
   typedef std::vector<MemoryDumpTriggerConfig> MemoryDumpConfig;
diff --git a/trace_event/trace_config_memory_test_util.h b/trace_event/trace_config_memory_test_util.h
new file mode 100644
index 0000000..5a64d28
--- /dev/null
+++ b/trace_event/trace_config_memory_test_util.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 BASE_TRACE_EVENT_TRACE_CONFIG_MEMORY_TEST_UTIL_H_
+#define BASE_TRACE_EVENT_TRACE_CONFIG_MEMORY_TEST_UTIL_H_
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_dump_manager.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceConfigMemoryTestUtil {
+ public:
+  static std::string GetTraceConfig_PeriodicTriggers(int light_period,
+                                                     int heavy_period) {
+    return StringPrintf(
+        "{"
+        "\"enable_argument_filter\":false,"
+        "\"enable_sampling\":false,"
+        "\"enable_systrace\":false,"
+        "\"included_categories\":["
+        "\"%s\""
+        "],"
+        "\"memory_dump_config\":{"
+        "\"triggers\":["
+        "{"
+        "\"mode\":\"light\","
+        "\"periodic_interval_ms\":%d"
+        "},"
+        "{"
+        "\"mode\":\"detailed\","
+        "\"periodic_interval_ms\":%d"
+        "}"
+        "]"
+        "},"
+        "\"record_mode\":\"record-until-full\""
+        "}",
+        MemoryDumpManager::kTraceCategory, light_period, heavy_period);
+  }
+
+  static std::string GetTraceConfig_EmptyTriggers() {
+    return StringPrintf(
+        "{"
+        "\"enable_argument_filter\":false,"
+        "\"enable_sampling\":false,"
+        "\"enable_systrace\":false,"
+        "\"included_categories\":["
+        "\"%s\""
+        "],"
+        "\"memory_dump_config\":{"
+        "\"triggers\":["
+        "]"
+        "},"
+        "\"record_mode\":\"record-until-full\""
+        "}",
+        MemoryDumpManager::kTraceCategory);
+  }
+
+  static std::string GetTraceConfig_NoTriggers() {
+    return StringPrintf(
+        "{"
+        "\"enable_argument_filter\":false,"
+        "\"enable_sampling\":false,"
+        "\"enable_systrace\":false,"
+        "\"included_categories\":["
+        "\"%s\""
+        "],"
+        "\"record_mode\":\"record-until-full\""
+        "}",
+        MemoryDumpManager::kTraceCategory);
+  }
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_CONFIG_MEMORY_TEST_UTIL_H_
diff --git a/trace_event/trace_config_unittest.cc b/trace_event/trace_config_unittest.cc
index 7d8881d..9622595 100644
--- a/trace_event/trace_config_unittest.cc
+++ b/trace_event/trace_config_unittest.cc
@@ -1,9 +1,10 @@
-// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// 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 "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/trace_config.h"
+#include "base/trace_event/trace_config_memory_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -20,44 +21,6 @@
     "\"record_mode\":\"record-until-full\""
   "}";
 
-const char kMemoryDumpTraceConfigString[] =
-    "{"
-    "\"enable_argument_filter\":false,"
-    "\"enable_sampling\":false,"
-    "\"enable_systrace\":false,"
-    "\"included_categories\":["
-    "\"disabled-by-default-memory-infra\""
-    "],"
-    "\"memory_dump_config\":{"
-    "\"triggers\":["
-    "{"
-    "\"mode\":\"light\","
-    "\"periodic_interval_ms\":200"
-    "},"
-    "{"
-    "\"mode\":\"detailed\","
-    "\"periodic_interval_ms\":2000"
-    "}"
-    "]"
-    "},"
-    "\"record_mode\":\"record-until-full\""
-    "}";
-
-const char kTraceConfigStringWithEmptyTriggers[] =
-    "{"
-    "\"enable_argument_filter\":false,"
-    "\"enable_sampling\":false,"
-    "\"enable_systrace\":false,"
-    "\"included_categories\":["
-    "\"disabled-by-default-memory-infra\""
-    "],"
-    "\"memory_dump_config\":{"
-    "\"triggers\":["
-    "]"
-    "},"
-    "\"record_mode\":\"record-until-full\""
-    "}";
-
 }  // namespace
 
 TEST(TraceConfigTest, TraceConfigFromValidLegacyFormat) {
@@ -528,24 +491,27 @@
 }
 
 TEST(TraceConfigTest, TraceConfigFromMemoryConfigString) {
-  TraceConfig tc(kMemoryDumpTraceConfigString);
-  EXPECT_STREQ(kMemoryDumpTraceConfigString, tc.ToString().c_str());
+  std::string tc_str =
+      TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(200, 2000);
+  TraceConfig tc(tc_str);
+  EXPECT_EQ(tc_str, tc.ToString());
   EXPECT_TRUE(tc.IsCategoryGroupEnabled(MemoryDumpManager::kTraceCategory));
   EXPECT_EQ(2u, tc.memory_dump_config_.size());
 
   EXPECT_EQ(200u, tc.memory_dump_config_[0].periodic_interval_ms);
-  EXPECT_EQ(MemoryDumpArgs::LevelOfDetail::LOW,
+  EXPECT_EQ(MemoryDumpLevelOfDetail::LIGHT,
             tc.memory_dump_config_[0].level_of_detail);
 
   EXPECT_EQ(2000u, tc.memory_dump_config_[1].periodic_interval_ms);
-  EXPECT_EQ(MemoryDumpArgs::LevelOfDetail::HIGH,
+  EXPECT_EQ(MemoryDumpLevelOfDetail::DETAILED,
             tc.memory_dump_config_[1].level_of_detail);
 }
 
 TEST(TraceConfigTest, EmptyMemoryDumpConfigTest) {
   // Empty trigger list should also be specified when converting back to string.
-  TraceConfig tc(kTraceConfigStringWithEmptyTriggers);
-  EXPECT_STREQ(kTraceConfigStringWithEmptyTriggers, tc.ToString().c_str());
+  TraceConfig tc(TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers());
+  EXPECT_EQ(TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers(),
+            tc.ToString());
   EXPECT_EQ(0u, tc.memory_dump_config_.size());
 }
 
diff --git a/trace_event/trace_event_etw_export_win.cc b/trace_event/trace_event_etw_export_win.cc
index 47935a4..c07c861 100644
--- a/trace_event/trace_event_etw_export_win.cc
+++ b/trace_event/trace_event_etw_export_win.cc
@@ -133,19 +133,18 @@
 // This object will be created by each process. It's a background (low-priority)
 // thread that will monitor the ETW keyword for any changes.
 class TraceEventETWExport::ETWKeywordUpdateThread
-    : public base::PlatformThread::Delegate {
+    : public PlatformThread::Delegate {
  public:
   ETWKeywordUpdateThread() {}
   ~ETWKeywordUpdateThread() override {}
 
   // Implementation of PlatformThread::Delegate:
   void ThreadMain() override {
-    base::PlatformThread::SetName("ETW Keyword Update Thread");
-    base::TimeDelta sleep_time =
-        base::TimeDelta::FromMilliseconds(kUpdateTimerDelayMs);
+    PlatformThread::SetName("ETW Keyword Update Thread");
+    TimeDelta sleep_time = TimeDelta::FromMilliseconds(kUpdateTimerDelayMs);
     while (1) {
-      base::PlatformThread::Sleep(sleep_time);
-      base::trace_event::TraceEventETWExport::UpdateETWKeyword();
+      PlatformThread::Sleep(sleep_time);
+      trace_event::TraceEventETWExport::UpdateETWKeyword();
     }
   }
 
diff --git a/trace_event/trace_event_etw_export_win.h b/trace_event/trace_event_etw_export_win.h
index c1eafff..7a1c029 100644
--- a/trace_event/trace_event_etw_export_win.h
+++ b/trace_event/trace_event_etw_export_win.h
@@ -12,11 +12,11 @@
 #include "base/strings/string_piece.h"
 #include "base/trace_event/trace_event_impl.h"
 
-// Fwd.
+namespace base {
+
 template <typename Type>
 struct StaticMemorySingletonTraits;
 
-namespace base {
 namespace trace_event {
 
 class BASE_EXPORT TraceEventETWExport {
@@ -86,7 +86,7 @@
   bool etw_export_enabled_;
 
   // Maps category names to their status (enabled/disabled).
-  std::map<base::StringPiece, bool> categories_status_;
+  std::map<StringPiece, bool> categories_status_;
 
   // Local copy of the ETW keyword.
   uint64 etw_match_any_keyword_;
diff --git a/trace_event/trace_event_memory_overhead.cc b/trace_event/trace_event_memory_overhead.cc
index bf957b0..3fa6e42 100644
--- a/trace_event/trace_event_memory_overhead.cc
+++ b/trace_event/trace_event_memory_overhead.cc
@@ -144,7 +144,7 @@
                    it.second.allocated_size_in_bytes);
     mad->AddScalar("resident_size", MemoryAllocatorDump::kUnitsBytes,
                    it.second.resident_size_in_bytes);
-    mad->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+    mad->AddScalar(MemoryAllocatorDump::kNameObjectCount,
                    MemoryAllocatorDump::kUnitsObjects, it.second.count);
   }
 }
diff --git a/trace_event/trace_event_synthetic_delay.cc b/trace_event/trace_event_synthetic_delay.cc
index bad79cc..cd0c364 100644
--- a/trace_event/trace_event_synthetic_delay.cc
+++ b/trace_event/trace_event_synthetic_delay.cc
@@ -24,7 +24,7 @@
   void ResetAllDelays();
 
   // TraceEventSyntheticDelayClock implementation.
-  base::TimeTicks Now() override;
+  TimeTicks Now() override;
 
  private:
   TraceEventSyntheticDelayRegistry();
@@ -34,7 +34,7 @@
   Lock lock_;
   TraceEventSyntheticDelay delays_[kMaxSyntheticDelays];
   TraceEventSyntheticDelay dummy_delay_;
-  base::subtle::Atomic32 delay_count_;
+  subtle::Atomic32 delay_count_;
 
   DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry);
 };
@@ -57,8 +57,7 @@
   clock_ = clock;
 }
 
-void TraceEventSyntheticDelay::SetTargetDuration(
-    base::TimeDelta target_duration) {
+void TraceEventSyntheticDelay::SetTargetDuration(TimeDelta target_duration) {
   AutoLock lock(lock_);
   target_duration_ = target_duration;
   trigger_count_ = 0;
@@ -85,7 +84,7 @@
   if (!target_duration_.ToInternalValue())
     return;
 
-  base::TimeTicks start_time = clock_->Now();
+  TimeTicks start_time = clock_->Now();
   {
     AutoLock lock(lock_);
     if (++begin_count_ != 1)
@@ -94,15 +93,15 @@
   }
 }
 
-void TraceEventSyntheticDelay::BeginParallel(base::TimeTicks* out_end_time) {
+void TraceEventSyntheticDelay::BeginParallel(TimeTicks* out_end_time) {
   // See note in Begin().
   ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
   if (!target_duration_.ToInternalValue()) {
-    *out_end_time = base::TimeTicks();
+    *out_end_time = TimeTicks();
     return;
   }
 
-  base::TimeTicks start_time = clock_->Now();
+  TimeTicks start_time = clock_->Now();
   {
     AutoLock lock(lock_);
     *out_end_time = CalculateEndTimeLocked(start_time);
@@ -115,7 +114,7 @@
   if (!target_duration_.ToInternalValue())
     return;
 
-  base::TimeTicks end_time;
+  TimeTicks end_time;
   {
     AutoLock lock(lock_);
     if (!begin_count_ || --begin_count_ != 0)
@@ -126,21 +125,21 @@
     ApplyDelay(end_time);
 }
 
-void TraceEventSyntheticDelay::EndParallel(base::TimeTicks end_time) {
+void TraceEventSyntheticDelay::EndParallel(TimeTicks end_time) {
   if (!end_time.is_null())
     ApplyDelay(end_time);
 }
 
-base::TimeTicks TraceEventSyntheticDelay::CalculateEndTimeLocked(
-    base::TimeTicks start_time) {
+TimeTicks TraceEventSyntheticDelay::CalculateEndTimeLocked(
+    TimeTicks start_time) {
   if (mode_ == ONE_SHOT && trigger_count_++)
-    return base::TimeTicks();
+    return TimeTicks();
   else if (mode_ == ALTERNATING && trigger_count_++ % 2)
-    return base::TimeTicks();
+    return TimeTicks();
   return start_time + target_duration_;
 }
 
-void TraceEventSyntheticDelay::ApplyDelay(base::TimeTicks end_time) {
+void TraceEventSyntheticDelay::ApplyDelay(TimeTicks end_time) {
   TRACE_EVENT0("synthetic_delay", name_.c_str());
   while (clock_->Now() < end_time) {
     // Busy loop.
@@ -161,14 +160,14 @@
     const char* name) {
   // Try to find an existing delay first without locking to make the common case
   // fast.
-  int delay_count = base::subtle::Acquire_Load(&delay_count_);
+  int delay_count = subtle::Acquire_Load(&delay_count_);
   for (int i = 0; i < delay_count; ++i) {
     if (!strcmp(name, delays_[i].name_.c_str()))
       return &delays_[i];
   }
 
   AutoLock lock(lock_);
-  delay_count = base::subtle::Acquire_Load(&delay_count_);
+  delay_count = subtle::Acquire_Load(&delay_count_);
   for (int i = 0; i < delay_count; ++i) {
     if (!strcmp(name, delays_[i].name_.c_str()))
       return &delays_[i];
@@ -180,19 +179,19 @@
     return &dummy_delay_;
 
   delays_[delay_count].Initialize(std::string(name), this);
-  base::subtle::Release_Store(&delay_count_, delay_count + 1);
+  subtle::Release_Store(&delay_count_, delay_count + 1);
   return &delays_[delay_count];
 }
 
-base::TimeTicks TraceEventSyntheticDelayRegistry::Now() {
-  return base::TimeTicks::Now();
+TimeTicks TraceEventSyntheticDelayRegistry::Now() {
+  return TimeTicks::Now();
 }
 
 void TraceEventSyntheticDelayRegistry::ResetAllDelays() {
   AutoLock lock(lock_);
-  int delay_count = base::subtle::Acquire_Load(&delay_count_);
+  int delay_count = subtle::Acquire_Load(&delay_count_);
   for (int i = 0; i < delay_count; ++i) {
-    delays_[i].SetTargetDuration(base::TimeDelta());
+    delays_[i].SetTargetDuration(TimeDelta());
     delays_[i].SetClock(this);
   }
 }
diff --git a/trace_event/trace_event_win.h b/trace_event/trace_event_win.h
index 4161361..e64be4d 100644
--- a/trace_event/trace_event_win.h
+++ b/trace_event/trace_event_win.h
@@ -12,11 +12,11 @@
 #include "base/trace_event/trace_event.h"
 #include "base/win/event_trace_provider.h"
 
-// Fwd.
+namespace base {
+
 template <typename Type>
 struct StaticMemorySingletonTraits;
 
-namespace base {
 namespace trace_event {
 
 // This EtwTraceProvider subclass implements ETW logging
diff --git a/trace_event/trace_log.cc b/trace_event/trace_log.cc
index 2822c37..519bb2b 100644
--- a/trace_event/trace_log.cc
+++ b/trace_event/trace_log.cc
@@ -39,18 +39,22 @@
 #include "base/trace_event/trace_event_win.h"
 #endif
 
-class DeleteTraceLogForTesting {
- public:
-  static void Delete() {
-    Singleton<base::trace_event::TraceLog,
-              LeakySingletonTraits<base::trace_event::TraceLog>>::OnExit(0);
-  }
-};
-
 // The thread buckets for the sampling profiler.
 BASE_EXPORT TRACE_EVENT_API_ATOMIC_WORD g_trace_state[3];
 
 namespace base {
+namespace internal {
+
+class DeleteTraceLogForTesting {
+ public:
+  static void Delete() {
+    Singleton<trace_event::TraceLog,
+              LeakySingletonTraits<trace_event::TraceLog>>::OnExit(0);
+  }
+};
+
+}  // namespace internal
+
 namespace trace_event {
 
 namespace {
@@ -1539,7 +1543,7 @@
 }
 
 void TraceLog::DeleteForTesting() {
-  DeleteTraceLogForTesting::Delete();
+  internal::DeleteTraceLogForTesting::Delete();
 }
 
 TraceEvent* TraceLog::GetEventByHandle(TraceEventHandle handle) {
diff --git a/trace_event/trace_log.h b/trace_event/trace_log.h
index 727e1cd..29f6aa0 100644
--- a/trace_event/trace_log.h
+++ b/trace_event/trace_log.h
@@ -25,11 +25,10 @@
       TRACE_EVENT_PHASE_INSTANT, name, reinterpret_cast<const void*>(id), \
       extra)
 
-template <typename Type>
-struct DefaultSingletonTraits;
-
 namespace base {
 
+template <typename Type>
+struct DefaultSingletonTraits;
 class RefCountedString;
 
 namespace trace_event {
diff --git a/trace_event/winheap_dump_provider_win.cc b/trace_event/winheap_dump_provider_win.cc
index 4390376..11f9dc4 100644
--- a/trace_event/winheap_dump_provider_win.cc
+++ b/trace_event/winheap_dump_provider_win.cc
@@ -35,7 +35,7 @@
   inner_dump->AddScalar(MemoryAllocatorDump::kNameSize,
                         MemoryAllocatorDump::kUnitsBytes,
                         heap_info.allocated_size);
-  inner_dump->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+  inner_dump->AddScalar(MemoryAllocatorDump::kNameObjectCount,
                         MemoryAllocatorDump::kUnitsObjects,
                         heap_info.block_count);
 }
diff --git a/trace_event/winheap_dump_provider_win_unittest.cc b/trace_event/winheap_dump_provider_win_unittest.cc
index 93ae299..2a072aa 100644
--- a/trace_event/winheap_dump_provider_win_unittest.cc
+++ b/trace_event/winheap_dump_provider_win_unittest.cc
@@ -15,7 +15,7 @@
 
 TEST(WinHeapDumpProviderTest, OnMemoryDump) {
   ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
-  MemoryDumpArgs dump_args = {MemoryDumpArgs::LevelOfDetail::HIGH};
+  MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
 
   WinHeapDumpProvider* winheap_dump_provider =
       WinHeapDumpProvider::GetInstance();
diff --git a/values.cc b/values.cc
index 5374d6c..aa8de36 100644
--- a/values.cc
+++ b/values.cc
@@ -351,6 +351,16 @@
 
 ///////////////////// DictionaryValue ////////////////////
 
+// static
+scoped_ptr<DictionaryValue> DictionaryValue::From(scoped_ptr<Value> value) {
+  DictionaryValue* out;
+  if (value && value->GetAsDictionary(&out)) {
+    ignore_result(value.release());
+    return make_scoped_ptr(out);
+  }
+  return nullptr;
+}
+
 DictionaryValue::DictionaryValue()
     : Value(TYPE_DICTIONARY) {
 }
@@ -869,6 +879,16 @@
 
 ///////////////////// ListValue ////////////////////
 
+// static
+scoped_ptr<ListValue> ListValue::From(scoped_ptr<Value> value) {
+  ListValue* out;
+  if (value && value->GetAsList(&out)) {
+    ignore_result(value.release());
+    return make_scoped_ptr(out);
+  }
+  return nullptr;
+}
+
 ListValue::ListValue() : Value(TYPE_LIST) {
 }
 
diff --git a/values.h b/values.h
index 0ff6217..5a3e220 100644
--- a/values.h
+++ b/values.h
@@ -209,6 +209,9 @@
 // are |std::string|s and should be UTF-8 encoded.
 class BASE_EXPORT DictionaryValue : public Value {
  public:
+  // Returns |value| if it is a dictionary, nullptr otherwise.
+  static scoped_ptr<DictionaryValue> From(scoped_ptr<Value> value);
+
   DictionaryValue();
   ~DictionaryValue() override;
 
@@ -386,6 +389,9 @@
   typedef ValueVector::iterator iterator;
   typedef ValueVector::const_iterator const_iterator;
 
+  // Returns |value| if it is a list, nullptr otherwise.
+  static scoped_ptr<ListValue> From(scoped_ptr<Value> value);
+
   ListValue();
   ~ListValue() override;
 
diff --git a/win/scoped_handle.h b/win/scoped_handle.h
index 97fd7a5..d1eb1d6 100644
--- a/win/scoped_handle.h
+++ b/win/scoped_handle.h
@@ -27,9 +27,13 @@
 
 // Generic wrapper for raw handles that takes care of closing handles
 // automatically. The class interface follows the style of
-// the ScopedFILE class with one addition:
+// the ScopedFILE class with two additions:
 //   - IsValid() method can tolerate multiple invalid handle values such as NULL
 //     and INVALID_HANDLE_VALUE (-1) for Win32 handles.
+//   - Set() (and the constructors and assignment operators that call it)
+//     preserve the Windows LastError code. This ensures that GetLastError() can
+//     be called after stashing a handle in a GenericScopedHandle object. Doing
+//     this explicitly is necessary because of bug 528394 and VC++ 2015.
 template <class Traits, class Verifier>
 class GenericScopedHandle {
   MOVE_ONLY_TYPE_FOR_CPP_03(GenericScopedHandle, RValue)
@@ -66,6 +70,8 @@
 
   void Set(Handle handle) {
     if (handle_ != handle) {
+      // Preserve old LastError to avoid bug 528394.
+      auto last_error = ::GetLastError();
       Close();
 
       if (Traits::IsHandleValid(handle)) {
@@ -73,6 +79,7 @@
         Verifier::StartTracking(handle, this, BASE_WIN_GET_CALLER,
                                 tracked_objects::GetProgramCounter());
       }
+      ::SetLastError(last_error);
     }
   }
 
diff --git a/win/scoped_handle_unittest.cc b/win/scoped_handle_unittest.cc
new file mode 100644
index 0000000..70431ac
--- /dev/null
+++ b/win/scoped_handle_unittest.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/scoped_handle.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(ScopedHandleTest, ScopedHandle) {
+  // Any illegal error code will do. We just need to test that it is preserved
+  // by ScopedHandle to avoid bug 528394.
+  const DWORD magic_error = 0x12345678;
+
+  HANDLE handle = ::CreateMutex(nullptr, FALSE, nullptr);
+  // Call SetLastError after creating the handle.
+  ::SetLastError(magic_error);
+  base::win::ScopedHandle handle_holder(handle);
+  EXPECT_EQ(magic_error, ::GetLastError());
+
+  // Create a new handle and then set LastError again.
+  handle = ::CreateMutex(nullptr, FALSE, nullptr);
+  ::SetLastError(magic_error);
+  handle_holder.Set(handle);
+  EXPECT_EQ(magic_error, ::GetLastError());
+
+  // Create a new handle and then set LastError again.
+  handle = ::CreateMutex(nullptr, FALSE, nullptr);
+  base::win::ScopedHandle handle_source(handle);
+  ::SetLastError(magic_error);
+  handle_holder = std::move(handle_source);
+  EXPECT_EQ(magic_error, ::GetLastError());
+}