Update from https://crrev.com/327068

This rolls in //base, //build and //sandbox/linux and updates other
things to match, in particular:

*) Update build_v8.patch
*) Add junit, mockito and roboelectric to DEPS for android test rules
*) Update DEPS for grit
*) Fix up various GN files for os->target_os rename
*) Fix up a few places that were using //base/float_util to use std::isnan
*) Fix up a few places using ApiCompatibilityUtil to use Android SDK directly

as well as a few miscellaneous fixes.

Many portions based on ncbray's work in
https://codereview.chromium.org/1108173002/

R=ncbray@chromium.org
TBR=ncbray@chromium.org

Review URL: https://codereview.chromium.org/1124763003
diff --git a/base/trace_event/BUILD.gn b/base/trace_event/BUILD.gn
index 479a918..4f3819d 100644
--- a/base/trace_event/BUILD.gn
+++ b/base/trace_event/BUILD.gn
@@ -4,13 +4,19 @@
 
 source_set("trace_event") {
   sources = [
-    "memory_allocator_attributes.h",
+    "java_heap_dump_provider_android.cc",
+    "java_heap_dump_provider_android.h",
+    "memory_allocator_attributes_type_info.cc",
+    "memory_allocator_attributes_type_info.h",
     "memory_allocator_dump.cc",
     "memory_allocator_dump.h",
     "memory_dump_manager.cc",
     "memory_dump_manager.h",
     "memory_dump_provider.cc",
     "memory_dump_provider.h",
+    "memory_dump_request_args.h",
+    "memory_dump_session_state.cc",
+    "memory_dump_session_state.h",
     "process_memory_dump.cc",
     "process_memory_dump.h",
     "process_memory_maps.cc",
@@ -25,6 +31,8 @@
     "trace_event_android.cc",
     "trace_event_argument.cc",
     "trace_event_argument.h",
+    "trace_event_etw_export_win.cc",
+    "trace_event_etw_export_win.h",
     "trace_event_impl.cc",
     "trace_event_impl.h",
     "trace_event_impl_constants.cc",
@@ -36,6 +44,8 @@
     "trace_event_system_stats_monitor.h",
     "trace_event_win.cc",
     "trace_event_win.h",
+    "winheap_dump_provider_win.cc",
+    "winheap_dump_provider_win.h",
   ]
 
   if (is_nacl) {
@@ -45,6 +55,13 @@
     ]
   }
 
+  if (is_linux || is_android) {
+    sources += [
+      "malloc_dump_provider.cc",
+      "malloc_dump_provider.h",
+    ]
+  }
+
   configs += [ "//base:base_implementation" ]
 
   deps = [
@@ -55,6 +72,10 @@
     "//base/third_party/dynamic_annotations",
   ]
 
+  if (is_win) {
+    deps += [ "//base/trace_event/etw_manifest:chrome_events_win" ]
+  }
+
   allow_circular_includes_from = [
     "//base/debug",
     "//base/memory",
@@ -67,6 +88,7 @@
 source_set("trace_event_unittests") {
   testonly = true
   sources = [
+    "memory_allocator_attributes_type_info_unittest.cc",
     "memory_allocator_dump_unittest.cc",
     "memory_dump_manager_unittest.cc",
     "process_memory_maps_dump_provider_unittest.cc",
@@ -77,6 +99,7 @@
     "trace_event_system_stats_monitor_unittest.cc",
     "trace_event_unittest.cc",
     "trace_event_win_unittest.cc",
+    "winheap_dump_provider_win_unittest.cc",
   ]
 
   deps = [
diff --git a/base/trace_event/OWNERS b/base/trace_event/OWNERS
index 3932776..aa1d675 100644
--- a/base/trace_event/OWNERS
+++ b/base/trace_event/OWNERS
@@ -1,3 +1,4 @@
 nduca@chromium.org
 dsinclair@chromium.org
+primiano@chromium.org
 per-file trace_event_android.cc=wangxianzhu@chromium.org
diff --git a/base/trace_event/etw_manifest/BUILD.gn b/base/trace_event/etw_manifest/BUILD.gn
new file mode 100644
index 0000000..07cf80e
--- /dev/null
+++ b/base/trace_event/etw_manifest/BUILD.gn
@@ -0,0 +1,37 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+assert(is_win, "This only runs on Windows.")
+
+# Makes the .h/.rc files from the .man file.
+action("chrome_events_win") {
+  visibility = [
+    "//base/trace_event/*",
+    "//chrome:main_dll",
+  ]
+  script = "build/message_compiler.py"
+
+  sources = [
+    "chrome_events_win.man",
+  ]
+
+  outputs = [
+    "$target_gen_dir/chrome_events_win.h",
+    "$target_gen_dir/chrome_events_win.rc",
+  ]
+
+  args = [
+    # Where to put the header.
+    "-h",
+    rebase_path("$target_gen_dir", root_build_dir),
+
+    # Where to put the .rc file.
+    "-r",
+    rebase_path("$target_gen_dir", root_build_dir),
+
+    # Generate the user-mode code.
+    "-um",
+    rebase_path("chrome_events_win.man", root_build_dir),
+  ]
+}
diff --git a/base/trace_event/etw_manifest/BUILD/message_compiler.py b/base/trace_event/etw_manifest/BUILD/message_compiler.py
new file mode 100644
index 0000000..be5927d
--- /dev/null
+++ b/base/trace_event/etw_manifest/BUILD/message_compiler.py
@@ -0,0 +1,16 @@
+# 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.
+
+# Runs the Microsoft Message Compiler (mc.exe). This Python adapter is for the
+# GN build, which can only run Python and not native binaries.
+
+import subprocess
+import sys
+
+# mc writes to stderr, so this explicily redirects to stdout and eats it.
+try:
+  subprocess.check_output(["mc.exe"] + sys.argv[1:], stderr=subprocess.STDOUT)
+except subprocess.CalledProcessError as e:
+  print e.output
+  sys.exit(e.returncode)
diff --git a/base/trace_event/etw_manifest/chrome_events_win.man b/base/trace_event/etw_manifest/chrome_events_win.man
new file mode 100644
index 0000000..10a8ddf
--- /dev/null
+++ b/base/trace_event/etw_manifest/chrome_events_win.man
@@ -0,0 +1,84 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes'?>
+<instrumentationManifest
+    xmlns="http://schemas.microsoft.com/win/2004/08/events"
+    xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events"
+    xmlns:xs="http://www.w3.org/2001/XMLSchema"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://schemas.microsoft.com/win/2004/08/events eventman.xsd"
+    >
+  <instrumentation>
+    <events>
+      <provider
+          guid="{D2D578D9-2936-45B6-A09f-30E32715F42D}"
+          messageFileName="chrome.dll"
+          name="Chrome"
+          resourceFileName="chrome.dll"
+          symbol="CHROME"
+          >
+        <channels>
+          <importChannel
+              chid="SYSTEM"
+              name="System"
+              />
+        </channels>
+        <templates>
+          <template tid="tid_chrome_event">
+            <data
+                inType="win:AnsiString"
+                name="Name"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Phase"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Arg Name 1"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Arg Value 1"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Arg Name 2"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Arg Value 2"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Arg Name 3"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Arg Value 3"
+                />
+          </template>
+        </templates>
+        <events>
+          <event
+              channel="SYSTEM"
+              level="win:Informational"
+              message="$(string.ChromeEvent.EventMessage)"
+              opcode="win:Info"
+              symbol="ChromeEvent"
+              template="tid_chrome_event"
+              value="1"
+              />
+        </events>
+      </provider>
+    </events>
+  </instrumentation>
+  <localization xmlns="http://schemas.microsoft.com/win/2004/08/events">
+    <resources culture="en-US">
+      <stringTable>
+        <string
+            id="ChromeEvent.EventMessage"
+            value="Chrome Event: %1 (%2)"
+            />
+      </stringTable>
+    </resources>
+  </localization>
+</instrumentationManifest>
diff --git a/base/trace_event/etw_manifest/etw_manifest.gyp b/base/trace_event/etw_manifest/etw_manifest.gyp
new file mode 100644
index 0000000..b0a8712
--- /dev/null
+++ b/base/trace_event/etw_manifest/etw_manifest.gyp
@@ -0,0 +1,39 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      # GN version: //base/trace_event/etw_manifest/BUILD.gn
+      'target_name': 'etw_manifest',
+      'type': 'static_library',
+      'conditions': [
+        ['OS=="win"', {
+          'sources': [
+            'chrome_events_win.man',
+          ],
+          'variables': {
+            'man_output_dir': '<(SHARED_INTERMEDIATE_DIR)/base/trace_event/etw_manifest',
+          },
+          'rules': [{
+            # Rule to run the message compiler.
+            'rule_name': 'message_compiler',
+            'extension': 'man',
+            'outputs': [
+              '<(man_output_dir)/chrome_events_win.h',
+              '<(man_output_dir)/chrome_events_win.rc',
+            ],
+            'action': [
+              'mc.exe',
+              '-h', '<(man_output_dir)',
+              '-r', '<(man_output_dir)/.',
+              '-um',
+              '<(RULE_INPUT_PATH)',
+            ],
+            'message': 'Running message compiler on <(RULE_INPUT_PATH)',
+          }],
+        }],
+      ],
+    }
+  ]
+}
diff --git a/base/trace_event/java_heap_dump_provider_android.cc b/base/trace_event/java_heap_dump_provider_android.cc
new file mode 100644
index 0000000..aa193ab
--- /dev/null
+++ b/base/trace_event/java_heap_dump_provider_android.cc
@@ -0,0 +1,53 @@
+// 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/java_heap_dump_provider_android.h"
+
+#include "base/android/java_runtime.h"
+#include "base/trace_event/process_memory_dump.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+const char kDumperFriendlyName[] = "JavaHeap";
+const char kDumperName[] = "java_heap";
+
+}  // namespace
+
+// static
+JavaHeapDumpProvider* JavaHeapDumpProvider::GetInstance() {
+  return Singleton<JavaHeapDumpProvider,
+                   LeakySingletonTraits<JavaHeapDumpProvider>>::get();
+}
+
+JavaHeapDumpProvider::JavaHeapDumpProvider() {
+}
+
+JavaHeapDumpProvider::~JavaHeapDumpProvider() {
+}
+
+// Called at trace dump point time. Creates a snapshot with the memory counters
+// for the current process.
+bool JavaHeapDumpProvider::DumpInto(ProcessMemoryDump* pmd) {
+  MemoryAllocatorDump* dump =
+      pmd->CreateAllocatorDump(kDumperName, MemoryAllocatorDump::kRootHeap);
+
+  // These numbers come from java.lang.Runtime stats.
+  long total_heap_size = 0;
+  long free_heap_size = 0;
+  android::JavaRuntime::GetMemoryUsage(&total_heap_size, &free_heap_size);
+  dump->set_physical_size_in_bytes(total_heap_size);
+  dump->set_allocated_objects_count(0);
+  dump->set_allocated_objects_size_in_bytes(total_heap_size - free_heap_size);
+  return true;
+}
+
+const char* JavaHeapDumpProvider::GetFriendlyName() const {
+  return kDumperFriendlyName;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/java_heap_dump_provider_android.h b/base/trace_event/java_heap_dump_provider_android.h
new file mode 100644
index 0000000..8280751
--- /dev/null
+++ b/base/trace_event/java_heap_dump_provider_android.h
@@ -0,0 +1,35 @@
+// 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_JAVA_HEAP_DUMP_PROVIDER_ANDROID_H_
+#define BASE_TRACE_EVENT_JAVA_HEAP_DUMP_PROVIDER_ANDROID_H_
+
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+namespace trace_event {
+
+// Dump provider which collects process-wide memory stats.
+class JavaHeapDumpProvider : public MemoryDumpProvider {
+ public:
+  static JavaHeapDumpProvider* GetInstance();
+
+  // MemoryDumpProvider implementation.
+  bool DumpInto(ProcessMemoryDump* pmd) override;
+  const char* GetFriendlyName() const override;
+
+ private:
+  friend struct DefaultSingletonTraits<JavaHeapDumpProvider>;
+
+  JavaHeapDumpProvider();
+  ~JavaHeapDumpProvider() override;
+
+  DISALLOW_COPY_AND_ASSIGN(JavaHeapDumpProvider);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_JAVA_HEAP_DUMP_PROVIDER_ANDROID_H_
diff --git a/base/trace_event/malloc_dump_provider.cc b/base/trace_event/malloc_dump_provider.cc
new file mode 100644
index 0000000..7d9931c
--- /dev/null
+++ b/base/trace_event/malloc_dump_provider.cc
@@ -0,0 +1,64 @@
+// 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/malloc_dump_provider.h"
+
+#include <malloc.h>
+
+#include "base/trace_event/process_memory_dump.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+const char kDumperFriendlyName[] = "Malloc";
+
+}  // namespace
+
+// static
+MallocDumpProvider* MallocDumpProvider::GetInstance() {
+  return Singleton<MallocDumpProvider,
+                   LeakySingletonTraits<MallocDumpProvider>>::get();
+}
+
+MallocDumpProvider::MallocDumpProvider() {
+}
+
+MallocDumpProvider::~MallocDumpProvider() {
+}
+
+// Called at trace dump point time. Creates a snapshot the memory counters for
+// the current process.
+bool MallocDumpProvider::DumpInto(ProcessMemoryDump* pmd) {
+  struct mallinfo info = mallinfo();
+  DCHECK_GE(info.arena + info.hblkhd, info.uordblks);
+
+  MemoryAllocatorDump* dump =
+      pmd->CreateAllocatorDump("malloc", MemoryAllocatorDump::kRootHeap);
+  if (!dump)
+    return false;
+
+  // When the system allocator is implemented by tcmalloc, the total physical
+  // size is given by |arena| and |hblkhd| is 0. In case of Android's jemalloc
+  // |arena| is 0 and the outer pages size is reported by |hblkhd|. In case of
+  // dlmalloc the total is given by |arena| + |hblkhd|.
+  // For more details see link: http://goo.gl/fMR8lF.
+  dump->set_physical_size_in_bytes(info.arena + info.hblkhd);
+
+  // mallinfo doesn't support any allocated object count.
+  dump->set_allocated_objects_count(0);
+
+  // Total allocated space is given by |uordblks|.
+  dump->set_allocated_objects_size_in_bytes(info.uordblks);
+
+  return true;
+}
+
+const char* MallocDumpProvider::GetFriendlyName() const {
+  return kDumperFriendlyName;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/malloc_dump_provider.h b/base/trace_event/malloc_dump_provider.h
new file mode 100644
index 0000000..b6f6973
--- /dev/null
+++ b/base/trace_event/malloc_dump_provider.h
@@ -0,0 +1,37 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_MALLOC_DUMP_PROVIDER_H_
+#define BASE_TRACE_EVENT_MALLOC_DUMP_PROVIDER_H_
+
+#include <istream>
+
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+namespace trace_event {
+
+// Dump provider which collects process-wide memory stats.
+class BASE_EXPORT MallocDumpProvider : public MemoryDumpProvider {
+ public:
+  static MallocDumpProvider* GetInstance();
+
+  // MemoryDumpProvider implementation.
+  bool DumpInto(ProcessMemoryDump* pmd) override;
+  const char* GetFriendlyName() const override;
+
+ private:
+  friend struct DefaultSingletonTraits<MallocDumpProvider>;
+
+  MallocDumpProvider();
+  ~MallocDumpProvider() override;
+
+  DISALLOW_COPY_AND_ASSIGN(MallocDumpProvider);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MALLOC_DUMP_PROVIDER_H_
diff --git a/base/trace_event/memory_allocator_attributes.h b/base/trace_event/memory_allocator_attributes.h
deleted file mode 100644
index efae9de..0000000
--- a/base/trace_event/memory_allocator_attributes.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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_MEMORY_ALLOCATOR_ATTRIBUTES_H_
-#define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_ATTRIBUTES_H_
-
-#include <string>
-
-#include "base/base_export.h"
-#include "base/containers/hash_tables.h"
-
-namespace base {
-namespace trace_event {
-
-struct BASE_EXPORT MemoryAllocatorDeclaredAttribute {
-  std::string name;
-
-  // Refer to src/tools/perf/unit-info.json for the semantic of the type.
-  std::string type;
-};
-
-using MemoryAllocatorDeclaredAttributes =
-    hash_map<std::string, MemoryAllocatorDeclaredAttribute>;
-
-}  // namespace trace_event
-}  // namespace base
-
-#endif  // BASE_TRACE_EVENT_MEMORY_ALLOCATOR_ATTRIBUTES_H_
diff --git a/base/trace_event/memory_allocator_attributes_type_info.cc b/base/trace_event/memory_allocator_attributes_type_info.cc
new file mode 100644
index 0000000..7d1e61c
--- /dev/null
+++ b/base/trace_event/memory_allocator_attributes_type_info.cc
@@ -0,0 +1,61 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_allocator_attributes_type_info.h"
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+base::LazyInstance<const std::string> kNotFound = LAZY_INSTANCE_INITIALIZER;
+
+std::string GetKey(const std::string& allocator_name,
+                   const std::string& attribute_name) {
+  return allocator_name + "/" + attribute_name;
+}
+}  // namespace
+
+MemoryAllocatorAttributesTypeInfo::MemoryAllocatorAttributesTypeInfo() {
+}
+
+MemoryAllocatorAttributesTypeInfo::~MemoryAllocatorAttributesTypeInfo() {
+}
+
+const std::string& MemoryAllocatorAttributesTypeInfo::Get(
+    const std::string& allocator_name,
+    const std::string& attribute_name) const {
+  auto it = type_info_map_.find(GetKey(allocator_name, attribute_name));
+  if (it == type_info_map_.end())
+    return kNotFound.Get();
+  return it->second;
+}
+
+void MemoryAllocatorAttributesTypeInfo::Set(const std::string& allocator_name,
+                                            const std::string& attribute_name,
+                                            const std::string& attribute_type) {
+  std::string key = GetKey(allocator_name, attribute_name);
+  DCHECK_EQ(0u, type_info_map_.count(key));
+  type_info_map_[key] = attribute_type;
+}
+
+bool MemoryAllocatorAttributesTypeInfo::Exists(
+    const std::string& allocator_name,
+    const std::string& attribute_name) const {
+  return type_info_map_.count(GetKey(allocator_name, attribute_name)) == 1;
+}
+
+void MemoryAllocatorAttributesTypeInfo::Update(
+    const MemoryAllocatorAttributesTypeInfo& other) {
+  for (auto it = other.type_info_map_.begin();
+       it != other.type_info_map_.end(); ++it) {
+    bool no_duplicates = type_info_map_.insert(*it).second;
+    DCHECK(no_duplicates) << "Duplicated allocator attribute " << it->first;
+  }
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/memory_allocator_attributes_type_info.h b/base/trace_event/memory_allocator_attributes_type_info.h
new file mode 100644
index 0000000..c3986ae
--- /dev/null
+++ b/base/trace_event/memory_allocator_attributes_type_info.h
@@ -0,0 +1,49 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_MEMORY_ALLOCATOR_ATTRIBUTES_TYPE_INFO_H_
+#define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_ATTRIBUTES_TYPE_INFO_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+
+namespace base {
+namespace trace_event {
+
+// A dictionary of "allocator_name/attribute_name" -> "attribute_type" which
+// supports merging and enforces duplicate checking.
+class BASE_EXPORT MemoryAllocatorAttributesTypeInfo {
+ public:
+  MemoryAllocatorAttributesTypeInfo();
+  ~MemoryAllocatorAttributesTypeInfo();
+
+  // Returns the attribute type, or an empty string if not found.
+  const std::string& Get(const std::string& allocator_name,
+                         const std::string& attribute_name) const;
+
+  // Refer to tools/perf/unit-info.json for the semantics of |attribute_type|.
+  void Set(const std::string& allocator_name,
+           const std::string& attribute_name,
+           const std::string& attribute_type);
+
+  // Checks whether a given {allocator_name, attribute_name} declaration exists.
+  bool Exists(const std::string& allocator_name,
+              const std::string& attribute_name) const;
+
+  // Merges the attribute types declared in |other| into this.
+  void Update(const MemoryAllocatorAttributesTypeInfo& other);
+
+ private:
+  // "allocator_name/attribute_name" -> attribute_type.
+  hash_map<std::string, std::string> type_info_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryAllocatorAttributesTypeInfo);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_ALLOCATOR_ATTRIBUTES_TYPE_INFO_H_
diff --git a/base/trace_event/memory_allocator_attributes_type_info_unittest.cc b/base/trace_event/memory_allocator_attributes_type_info_unittest.cc
new file mode 100644
index 0000000..5f69fae
--- /dev/null
+++ b/base/trace_event/memory_allocator_attributes_type_info_unittest.cc
@@ -0,0 +1,59 @@
+// 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_allocator_attributes_type_info.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(MemoryAllocatorAttributesTypeInfoTest, BasicTest) {
+  MemoryAllocatorAttributesTypeInfo attrs;
+  EXPECT_EQ("", attrs.Get("non_existing_alloc", "non_existing_attr"));
+
+  attrs.Set("alloc", "attr", "type");
+  EXPECT_TRUE(attrs.Exists("alloc", "attr"));
+  EXPECT_FALSE(attrs.Exists("alloc", "foo"));
+  EXPECT_FALSE(attrs.Exists("foo", "attr"));
+  EXPECT_EQ("type", attrs.Get("alloc", "attr"));
+
+  attrs.Set("alloc2", "attr", "type2");
+  EXPECT_TRUE(attrs.Exists("alloc2", "attr"));
+  EXPECT_FALSE(attrs.Exists("alloc2", "foo"));
+  EXPECT_EQ("type", attrs.Get("alloc", "attr"));
+  EXPECT_EQ("type2", attrs.Get("alloc2", "attr"));
+
+  MemoryAllocatorAttributesTypeInfo other_attrs;
+  other_attrs.Set("other_alloc", "other_attr", "other_type");
+  other_attrs.Set("other_alloc", "attr", "other_type2");
+  other_attrs.Set("other_alloc_2", "other_attr", "other_type");
+  other_attrs.Set("other_alloc_2", "attr", "other_type3");
+
+  // Check the merging logic.
+  attrs.Update(other_attrs);
+  EXPECT_EQ("other_type", attrs.Get("other_alloc", "other_attr"));
+  EXPECT_EQ("other_type2", attrs.Get("other_alloc", "attr"));
+  EXPECT_EQ("other_type", attrs.Get("other_alloc_2", "other_attr"));
+  EXPECT_EQ("other_type3", attrs.Get("other_alloc_2", "attr"));
+  EXPECT_EQ("type", attrs.Get("alloc", "attr"));
+  EXPECT_EQ("type2", attrs.Get("alloc2", "attr"));
+  EXPECT_FALSE(other_attrs.Exists("alloc", "attr"));
+  EXPECT_FALSE(other_attrs.Exists("alloc2", "attr"));
+}
+
+// DEATH tests are not supported in Android / iOS.
+#if !defined(NDEBUG) && !defined(OS_ANDROID) && !defined(OS_IOS)
+TEST(MemoryAllocatorAttributesTypeInfoTest, DuplicatesDeathTest) {
+  MemoryAllocatorAttributesTypeInfo attrs;
+  attrs.Set("alloc", "attr", "type");
+  MemoryAllocatorAttributesTypeInfo conflicting_attrs;
+  conflicting_attrs.Set("alloc", "attr", "type2");
+  ASSERT_DEATH(attrs.Set("alloc", "attr", "other_type"), "");
+  ASSERT_DEATH(attrs.Update(conflicting_attrs), "");
+}
+#endif
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/memory_allocator_dump.cc b/base/trace_event/memory_allocator_dump.cc
index 604af7a..1d2fb3f 100644
--- a/base/trace_event/memory_allocator_dump.cc
+++ b/base/trace_event/memory_allocator_dump.cc
@@ -6,85 +6,122 @@
 
 #include "base/format_macros.h"
 #include "base/strings/stringprintf.h"
-#include "base/trace_event/memory_allocator_attributes.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "base/values.h"
 
 namespace base {
 namespace trace_event {
 
-MemoryAllocatorDump::MemoryAllocatorDump(const std::string& name,
-                                         MemoryAllocatorDump* parent)
-    : name_(name),
-      parent_(parent),
+// static
+const char MemoryAllocatorDump::kRootHeap[] = "";
+
+// static
+std::string MemoryAllocatorDump::GetAbsoluteName(
+    const std::string& allocator_name,
+    const std::string& heap_name) {
+  return allocator_name + (heap_name == kRootHeap ? "" : "/" + heap_name);
+}
+
+MemoryAllocatorDump::MemoryAllocatorDump(const std::string& allocator_name,
+                                         const std::string& heap_name,
+                                         ProcessMemoryDump* process_memory_dump)
+    : allocator_name_(allocator_name),
+      heap_name_(heap_name),
+      process_memory_dump_(process_memory_dump),
       physical_size_in_bytes_(0),
       allocated_objects_count_(0),
       allocated_objects_size_in_bytes_(0) {
-  // Dots are not allowed in the name as the underlying base::DictionaryValue
+  // The allocator name cannot be empty or contain slash separators.
+  DCHECK(!allocator_name.empty());
+  DCHECK_EQ(std::string::npos, allocator_name.find_first_of('/'));
+
+  // The heap_name can be empty and contain slash separator, but not
+  // leading or trailing ones.
+  DCHECK(heap_name.empty() ||
+         (heap_name[0] != '/' && *heap_name.rbegin() != '/'));
+
+  // Dots are not allowed anywhere as the underlying base::DictionaryValue
   // would treat them magically and split in sub-nodes, which is not intended.
-  DCHECK_EQ(std::string::npos, name.find_first_of('.'));
+  DCHECK_EQ(std::string::npos, allocator_name.find_first_of('.'));
+  DCHECK_EQ(std::string::npos, heap_name.find_first_of('.'));
 }
 
 MemoryAllocatorDump::~MemoryAllocatorDump() {
 }
 
-void MemoryAllocatorDump::SetExtraAttribute(const std::string& name,
-                                            int value) {
-  extra_attributes_.SetInteger(name, value);
+void MemoryAllocatorDump::SetAttribute(const std::string& name, int value) {
+  DCHECK(GetAttributesTypeInfo().Exists(allocator_name_, name))
+      << "attribute '" << name << "' not declared."
+      << "See MemoryDumpProvider.DeclareAllocatorAttribute()";
+  attributes_values_.SetInteger(name, value);
 }
 
-int MemoryAllocatorDump::GetExtraIntegerAttribute(
-    const std::string& name) const {
-  bool res;
+std::string MemoryAllocatorDump::GetAbsoluteName() const {
+  return GetAbsoluteName(allocator_name_, heap_name_);
+}
+
+int MemoryAllocatorDump::GetIntegerAttribute(const std::string& name) const {
   int value = -1;
-  res = extra_attributes_.GetInteger(name, &value);
-  DCHECK(res) << "Allocator attribute '" << name << "' not found";
+  bool res = attributes_values_.GetInteger(name, &value);
+  DCHECK(res) << "Attribute '" << name << "' not found";
   return value;
 }
 
 void MemoryAllocatorDump::AsValueInto(TracedValue* value) const {
   static const char kHexFmt[] = "%" PRIx64;
 
-  value->BeginDictionary(name_.c_str());
+  value->BeginDictionary(GetAbsoluteName().c_str());
+  value->BeginDictionary("attrs");
 
-  value->SetString("parent", parent_ ? parent_->name_ : "");
-  value->SetString("physical_size_in_bytes",
-                   StringPrintf(kHexFmt, physical_size_in_bytes_));
-  value->SetString("allocated_objects_count",
-                   StringPrintf(kHexFmt, allocated_objects_count_));
-  value->SetString("allocated_objects_size_in_bytes",
+  // TODO(primiano): these hard-coded types are temporary to transition to the
+  // new generalized attribute format. This code will be refactored by the end
+  // of May 2015.
+  value->BeginDictionary("outer_size");
+  value->SetString("type", "scalar");
+  value->SetString("units", "bytes");
+  value->SetString("value", StringPrintf(kHexFmt, physical_size_in_bytes_));
+  value->EndDictionary();
+
+  value->BeginDictionary("inner_size");
+  value->SetString("type", "scalar");
+  value->SetString("units", "bytes");
+  value->SetString("value",
                    StringPrintf(kHexFmt, allocated_objects_size_in_bytes_));
+  value->EndDictionary();
+
+  value->BeginDictionary("objects_count");
+  value->SetString("type", "scalar");
+  value->SetString("units", "objects");
+  value->SetString("value", StringPrintf(kHexFmt, allocated_objects_count_));
+  value->EndDictionary();
 
   // Copy all the extra attributes.
-  const MemoryDumpProvider* mdp =
-      MemoryDumpManager::GetInstance()->dump_provider_currently_active();
-  const MemoryAllocatorDeclaredAttributes& extra_attributes_types =
-      mdp->allocator_attributes();
-
-  value->BeginDictionary("args");
-  for (DictionaryValue::Iterator it(extra_attributes_); !it.IsAtEnd();
+  for (DictionaryValue::Iterator it(attributes_values_); !it.IsAtEnd();
        it.Advance()) {
     const std::string& attr_name = it.key();
     const Value& attr_value = it.value();
     value->BeginDictionary(attr_name.c_str());
     value->SetValue("value", attr_value.DeepCopy());
 
-    auto attr_it = extra_attributes_types.find(attr_name);
-    DCHECK(attr_it != extra_attributes_types.end())
-        << "Allocator attribute " << attr_name
-        << " not declared for the dumper " << mdp->GetFriendlyName();
-
-    // TODO(primiano): the "type" should be dumped just once, not repeated on
-    // on every event. The ability of doing so depends on crbug.com/466121.
-    value->SetString("type", attr_it->second.type);
+    const std::string& attr_type =
+        GetAttributesTypeInfo().Get(allocator_name_, attr_name);
+    DCHECK(!attr_type.empty());
+    value->SetString("type", "scalar");
+    value->SetString("units", attr_type);
 
     value->EndDictionary();  // "arg_name": { "type": "...", "value": "..." }
   }
-  value->EndDictionary();  // "args": {}
 
-  value->EndDictionary();  // "allocator name": {}
+  value->EndDictionary();  // "attrs": { ... }
+  value->EndDictionary();  // "allocator_name/heap_subheap": { ... }
+}
+
+const MemoryAllocatorAttributesTypeInfo&
+MemoryAllocatorDump::GetAttributesTypeInfo() const {
+  return process_memory_dump_->session_state()->allocators_attributes_type_info;
 }
 
 }  // namespace trace_event
diff --git a/base/trace_event/memory_allocator_dump.h b/base/trace_event/memory_allocator_dump.h
index 4d7293e..1c786ab 100644
--- a/base/trace_event/memory_allocator_dump.h
+++ b/base/trace_event/memory_allocator_dump.h
@@ -8,34 +8,45 @@
 #include "base/base_export.h"
 #include "base/basictypes.h"
 #include "base/logging.h"
-#include "base/trace_event/memory_allocator_attributes.h"
+#include "base/trace_event/memory_allocator_attributes_type_info.h"
 #include "base/values.h"
 
 namespace base {
 namespace trace_event {
 
 class MemoryDumpManager;
+class ProcessMemoryDump;
 class TracedValue;
 
 // Data model for user-land memory allocator dumps.
 class BASE_EXPORT MemoryAllocatorDump {
  public:
-  MemoryAllocatorDump(const std::string& name, MemoryAllocatorDump* parent);
+  // Returns the absolute name for a given (|allocator_name|,|heap_name|) tuple.
+  static std::string GetAbsoluteName(const std::string& allocator_name,
+                                     const std::string& heap_name);
+
+  // Use as argument for |heap_name| when the allocator has only one root heap.
+  static const char kRootHeap[];
+
+  // MemoryAllocatorDump is owned by ProcessMemoryDump.
+  MemoryAllocatorDump(const std::string& allocator_name,
+                      const std::string& heap_name,
+                      ProcessMemoryDump* process_memory_dump);
   ~MemoryAllocatorDump();
 
-  const std::string& name() const { return name_; }
-  const MemoryAllocatorDump* parent() const { return parent_; }
+  // Name of the allocator, a plain string with no separators (e.g, "malloc").
+  const std::string& allocator_name() const { return allocator_name_; }
 
-  void set_physical_size_in_bytes(uint64 value) {
-    physical_size_in_bytes_ = value;
-  }
-  uint64 physical_size_in_bytes() const { return physical_size_in_bytes_; }
+  // Name of the heap being dumped, either: "heap", "heap/subheap" or kRootHeap
+  // if the allocator has just one root heap.
+  const std::string& heap_name() const { return heap_name_; }
 
-  void set_allocated_objects_count(uint64 value) {
-    allocated_objects_count_ = value;
-  }
-  uint64 allocated_objects_count() const { return allocated_objects_count_; }
+  // Absolute name, unique within the scope of an entire ProcessMemoryDump.
+  // In practice this is "allocator_name/heap/subheap".
+  std::string GetAbsoluteName() const;
 
+  // Inner size: Bytes requested by clients of the allocator, without accounting
+  // for any metadata or allocator-specific bookeeping structs.
   void set_allocated_objects_size_in_bytes(uint64 value) {
     allocated_objects_size_in_bytes_ = value;
   }
@@ -43,19 +54,46 @@
     return allocated_objects_size_in_bytes_;
   }
 
-  void SetExtraAttribute(const std::string& name, int value);
-  int GetExtraIntegerAttribute(const std::string& name) const;
+  // Outer size: bytes requested to the system to handle all the allocations,
+  // including any allocator-internal metadata / bookeeping structs. For
+  // instance, in the case of an allocator which gets pages to the system via
+  // mmap() or similar, this is the number of requested pages * 4k.
+  void set_physical_size_in_bytes(uint64 value) {
+    physical_size_in_bytes_ = value;
+  }
+  uint64 physical_size_in_bytes() const { return physical_size_in_bytes_; }
+
+  // Number of objects allocated, if known, or 0 if not available.
+  void set_allocated_objects_count(uint64 value) {
+    allocated_objects_count_ = value;
+  }
+  uint64 allocated_objects_count() const { return allocated_objects_count_; }
+
+  // Get/Set extra attributes. The attributes name must have been previously
+  // declared through MemoryDumpProvider.DeclareAllocatorAttribute().
+  void SetAttribute(const std::string& name, int value);
+  int GetIntegerAttribute(const std::string& name) const;
 
   // Called at trace generation time to populate the TracedValue.
   void AsValueInto(TracedValue* value) const;
 
+  // Get the ProcessMemoryDump instance that owns this.
+  ProcessMemoryDump* process_memory_dump() const {
+    return process_memory_dump_;
+  }
+
+  // Retrieves the map of allocator attributes types, which is shared by all
+  // MemoryAllocatorDump(s) across all ProcessMemoryDump(s) per tracing session.
+  const MemoryAllocatorAttributesTypeInfo& GetAttributesTypeInfo() const;
+
  private:
-  const std::string name_;
-  MemoryAllocatorDump* const parent_;  // Not owned.
+  const std::string allocator_name_;
+  const std::string heap_name_;
+  ProcessMemoryDump* const process_memory_dump_;  // Not owned (PMD owns this).
   uint64 physical_size_in_bytes_;
   uint64 allocated_objects_count_;
   uint64 allocated_objects_size_in_bytes_;
-  DictionaryValue extra_attributes_;
+  DictionaryValue attributes_values_;
 
   DISALLOW_COPY_AND_ASSIGN(MemoryAllocatorDump);
 };
diff --git a/base/trace_event/memory_allocator_dump_unittest.cc b/base/trace_event/memory_allocator_dump_unittest.cc
index 8c14560..110a25d 100644
--- a/base/trace_event/memory_allocator_dump_unittest.cc
+++ b/base/trace_event/memory_allocator_dump_unittest.cc
@@ -5,89 +5,110 @@
 #include "base/trace_event/memory_allocator_dump.h"
 
 #include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/memory_dump_session_state.h"
 #include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_event_argument.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
 namespace trace_event {
 
 namespace {
+
 class FakeMemoryAllocatorDumpProvider : public MemoryDumpProvider {
  public:
   FakeMemoryAllocatorDumpProvider() {
-    DeclareAllocatorAttribute({"attr1", "count"});
-    DeclareAllocatorAttribute({"attr2", "bytes"});
+    DeclareAllocatorAttribute("foobar_allocator", "attr1", "count");
+    DeclareAllocatorAttribute("foobar_allocator", "attr2", "bytes");
   }
 
   bool DumpInto(ProcessMemoryDump* pmd) override {
-    MemoryAllocatorDump* mad_foo = pmd->CreateAllocatorDump("foo");
-    mad_foo->set_physical_size_in_bytes(4096);
-    mad_foo->set_allocated_objects_count(42);
-    mad_foo->set_allocated_objects_size_in_bytes(1000);
-    mad_foo->SetExtraAttribute("attr1", 1234);
-    mad_foo->SetExtraAttribute("attr2", 99);
+    MemoryAllocatorDump* root_heap = pmd->CreateAllocatorDump(
+        "foobar_allocator", MemoryAllocatorDump::kRootHeap);
+    root_heap->set_physical_size_in_bytes(4096);
+    root_heap->set_allocated_objects_count(42);
+    root_heap->set_allocated_objects_size_in_bytes(1000);
+    root_heap->SetAttribute("attr1", 1234);
+    root_heap->SetAttribute("attr2", 99);
 
-    MemoryAllocatorDump* mad_bar = pmd->CreateAllocatorDump("foo/bar", mad_foo);
-    mad_bar->set_physical_size_in_bytes(1);
-    mad_bar->set_allocated_objects_count(2);
-    mad_bar->set_allocated_objects_size_in_bytes(3);
+    MemoryAllocatorDump* sub_heap =
+        pmd->CreateAllocatorDump("foobar_allocator", "sub_heap");
+    sub_heap->set_physical_size_in_bytes(1);
+    sub_heap->set_allocated_objects_count(2);
+    sub_heap->set_allocated_objects_size_in_bytes(3);
 
-    pmd->CreateAllocatorDump("baz");
-    // Leave the rest of |baz| deliberately uninitialized, to check that
+    pmd->CreateAllocatorDump("foobar_allocator", "sub_heap/empty");
+    // Leave the rest of sub heap deliberately uninitialized, to check that
     // CreateAllocatorDump returns a properly zero-initialized object.
 
     return true;
   }
 
-  const char* GetFriendlyName() const override { return "mock_allocator"; }
+  const char* GetFriendlyName() const override { return "FooBar Allocator"; }
 };
 }  // namespace
 
 TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) {
   FakeMemoryAllocatorDumpProvider fmadp;
-  ProcessMemoryDump pmd;
+  ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+  pmd.session_state()->allocators_attributes_type_info.Update(
+      fmadp.allocator_attributes_type_info());
 
   fmadp.DumpInto(&pmd);
 
   ASSERT_EQ(3u, pmd.allocator_dumps().size());
 
-  const MemoryAllocatorDump* mad_foo = pmd.GetAllocatorDump("foo");
-  ASSERT_NE(nullptr, mad_foo);
-  EXPECT_EQ("foo", mad_foo->name());
-  ASSERT_EQ(nullptr, mad_foo->parent());
-  EXPECT_EQ(4096u, mad_foo->physical_size_in_bytes());
-  EXPECT_EQ(42u, mad_foo->allocated_objects_count());
-  EXPECT_EQ(1000u, mad_foo->allocated_objects_size_in_bytes());
+  const MemoryAllocatorDump* root_heap =
+      pmd.GetAllocatorDump("foobar_allocator", MemoryAllocatorDump::kRootHeap);
+  ASSERT_NE(nullptr, root_heap);
+  EXPECT_EQ("foobar_allocator", root_heap->allocator_name());
+  EXPECT_EQ("", root_heap->heap_name());
+  EXPECT_NE("", root_heap->GetAbsoluteName());
+  EXPECT_EQ(4096u, root_heap->physical_size_in_bytes());
+  EXPECT_EQ(42u, root_heap->allocated_objects_count());
+  EXPECT_EQ(1000u, root_heap->allocated_objects_size_in_bytes());
 
-  // Check the extra attributes of |mad_foo|.
-  EXPECT_EQ(1234, mad_foo->GetExtraIntegerAttribute("attr1"));
-  EXPECT_EQ(99, mad_foo->GetExtraIntegerAttribute("attr2"));
+  // Check the extra attributes of |root_heap|.
+  EXPECT_EQ(1234, root_heap->GetIntegerAttribute("attr1"));
+  EXPECT_EQ(99, root_heap->GetIntegerAttribute("attr2"));
 
-  const MemoryAllocatorDump* mad_bar = pmd.GetAllocatorDump("foo/bar");
-  ASSERT_NE(nullptr, mad_bar);
-  EXPECT_EQ("foo/bar", mad_bar->name());
-  ASSERT_EQ(mad_foo, mad_bar->parent());
-  EXPECT_EQ(1u, mad_bar->physical_size_in_bytes());
-  EXPECT_EQ(2u, mad_bar->allocated_objects_count());
-  EXPECT_EQ(3u, mad_bar->allocated_objects_size_in_bytes());
+  const MemoryAllocatorDump* sub_heap =
+      pmd.GetAllocatorDump("foobar_allocator", "sub_heap");
+  ASSERT_NE(nullptr, sub_heap);
+  EXPECT_EQ("foobar_allocator", sub_heap->allocator_name());
+  EXPECT_EQ("sub_heap", sub_heap->heap_name());
+  EXPECT_NE("", sub_heap->GetAbsoluteName());
+  EXPECT_EQ(1u, sub_heap->physical_size_in_bytes());
+  EXPECT_EQ(2u, sub_heap->allocated_objects_count());
+  EXPECT_EQ(3u, sub_heap->allocated_objects_size_in_bytes());
 
-  const MemoryAllocatorDump* mad_baz = pmd.GetAllocatorDump("baz");
-  ASSERT_NE(nullptr, mad_baz);
-  EXPECT_EQ("baz", mad_baz->name());
-  ASSERT_EQ(nullptr, mad_baz->parent());
-  EXPECT_EQ(0u, mad_baz->physical_size_in_bytes());
-  EXPECT_EQ(0u, mad_baz->allocated_objects_count());
-  EXPECT_EQ(0u, mad_baz->allocated_objects_size_in_bytes());
+  const MemoryAllocatorDump* empty_sub_heap =
+      pmd.GetAllocatorDump("foobar_allocator", "sub_heap/empty");
+  ASSERT_NE(nullptr, empty_sub_heap);
+  EXPECT_EQ("foobar_allocator", empty_sub_heap->allocator_name());
+  EXPECT_EQ("sub_heap/empty", empty_sub_heap->heap_name());
+  EXPECT_NE("", sub_heap->GetAbsoluteName());
+  EXPECT_EQ(0u, empty_sub_heap->physical_size_in_bytes());
+  EXPECT_EQ(0u, empty_sub_heap->allocated_objects_count());
+  EXPECT_EQ(0u, empty_sub_heap->allocated_objects_size_in_bytes());
+
+  // Check that the AsValueInfo doesn't hit any DCHECK.
+  scoped_refptr<TracedValue> traced_value(new TracedValue());
+  pmd.AsValueInto(traced_value.get());
 }
 
 // DEATH tests are not supported in Android / iOS.
 #if !defined(NDEBUG) && !defined(OS_ANDROID) && !defined(OS_IOS)
 TEST(MemoryAllocatorDumpTest, ForbidDuplicatesDeathTest) {
   FakeMemoryAllocatorDumpProvider fmadp;
-  ProcessMemoryDump pmd;
-  pmd.CreateAllocatorDump("dump_1");
-  pmd.CreateAllocatorDump("dump_2");
-  ASSERT_DEATH(pmd.CreateAllocatorDump("dump_1"), "");
+  ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+  pmd.CreateAllocatorDump("foo_allocator", MemoryAllocatorDump::kRootHeap);
+  pmd.CreateAllocatorDump("bar_allocator", "heap");
+  ASSERT_DEATH(
+      pmd.CreateAllocatorDump("foo_allocator", MemoryAllocatorDump::kRootHeap),
+      "");
+  ASSERT_DEATH(pmd.CreateAllocatorDump("bar_allocator", "heap"), "");
+  ASSERT_DEATH(pmd.CreateAllocatorDump("", "must_have_allocator_name"), "");
 }
 #endif
 
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 0ec5d19..859e8e0 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -9,41 +9,123 @@
 #include "base/atomic_sequence_num.h"
 #include "base/compiler_specific.h"
 #include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/memory_dump_session_state.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event_argument.h"
 
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+#include "base/trace_event/malloc_dump_provider.h"
+#include "base/trace_event/process_memory_maps_dump_provider.h"
+#include "base/trace_event/process_memory_totals_dump_provider.h"
+#elif defined(OS_WIN)
+#include "base/trace_event/winheap_dump_provider_win.h"
+#endif
+
 namespace base {
 namespace trace_event {
 
 namespace {
 
+// TODO(primiano): this should be smarter and should do something similar to
+// trace event synthetic delays.
+const char kTraceCategory[] = TRACE_DISABLED_BY_DEFAULT("memory-infra");
+
 MemoryDumpManager* g_instance_for_testing = nullptr;
+const int kDumpIntervalSeconds = 2;
 const int kTraceEventNumArgs = 1;
 const char* kTraceEventArgNames[] = {"dumps"};
 const unsigned char kTraceEventArgTypes[] = {TRACE_VALUE_TYPE_CONVERTABLE};
 StaticAtomicSequenceNumber g_next_guid;
 
-const char* DumpPointTypeToString(const DumpPointType& dump_point_type) {
-  switch (dump_point_type) {
-    case DumpPointType::TASK_BEGIN:
+const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type) {
+  switch (dump_type) {
+    case MemoryDumpType::TASK_BEGIN:
       return "TASK_BEGIN";
-    case DumpPointType::TASK_END:
+    case MemoryDumpType::TASK_END:
       return "TASK_END";
-    case DumpPointType::PERIODIC_INTERVAL:
+    case MemoryDumpType::PERIODIC_INTERVAL:
       return "PERIODIC_INTERVAL";
-    case DumpPointType::EXPLICITLY_TRIGGERED:
+    case MemoryDumpType::EXPLICITLY_TRIGGERED:
       return "EXPLICITLY_TRIGGERED";
   }
   NOTREACHED();
   return "UNKNOWN";
 }
 
+// Internal class used to hold details about ProcessMemoryDump requests for the
+// current process.
+// TODO(primiano): In the upcoming CLs, ProcessMemoryDump will become async.
+// and this class will be used to convey more details across PostTask()s.
+class ProcessMemoryDumpHolder
+    : public RefCountedThreadSafe<ProcessMemoryDumpHolder> {
+ public:
+  ProcessMemoryDumpHolder(
+      MemoryDumpRequestArgs req_args,
+      const scoped_refptr<MemoryDumpSessionState>& session_state,
+      MemoryDumpCallback callback)
+      : process_memory_dump(session_state),
+        req_args(req_args),
+        callback(callback),
+        task_runner(MessageLoop::current()->task_runner()),
+        num_pending_async_requests(0) {}
+
+  ProcessMemoryDump process_memory_dump;
+  const MemoryDumpRequestArgs req_args;
+
+  // Callback passed to the initial call to CreateProcessDump().
+  MemoryDumpCallback callback;
+
+  // Thread on which FinalizeDumpAndAddToTrace() should be called, which is the
+  // same that invoked the initial CreateProcessDump().
+  const scoped_refptr<SingleThreadTaskRunner> task_runner;
+
+  // Number of pending ContinueAsyncProcessDump() calls.
+  int num_pending_async_requests;
+
+ private:
+  friend class RefCountedThreadSafe<ProcessMemoryDumpHolder>;
+  virtual ~ProcessMemoryDumpHolder() {}
+  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpHolder);
+};
+
+void FinalizeDumpAndAddToTrace(
+    const scoped_refptr<ProcessMemoryDumpHolder>& pmd_holder) {
+  DCHECK_EQ(0, pmd_holder->num_pending_async_requests);
+
+  if (!pmd_holder->task_runner->BelongsToCurrentThread()) {
+    pmd_holder->task_runner->PostTask(
+        FROM_HERE, Bind(&FinalizeDumpAndAddToTrace, pmd_holder));
+    return;
+  }
+
+  scoped_refptr<ConvertableToTraceFormat> event_value(new TracedValue());
+  pmd_holder->process_memory_dump.AsValueInto(
+      static_cast<TracedValue*>(event_value.get()));
+  const char* const event_name =
+      MemoryDumpTypeToString(pmd_holder->req_args.dump_type);
+
+  TRACE_EVENT_API_ADD_TRACE_EVENT(
+      TRACE_EVENT_PHASE_MEMORY_DUMP,
+      TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name,
+      pmd_holder->req_args.dump_guid, kTraceEventNumArgs, kTraceEventArgNames,
+      kTraceEventArgTypes, nullptr /* arg_values */, &event_value,
+      TRACE_EVENT_FLAG_HAS_ID);
+
+  if (!pmd_holder->callback.is_null()) {
+    pmd_holder->callback.Run(pmd_holder->req_args.dump_guid, true);
+    pmd_holder->callback.Reset();
+  }
+}
+
+void RequestPeriodicGlobalDump() {
+  MemoryDumpManager::GetInstance()->RequestGlobalDump(
+      MemoryDumpType::PERIODIC_INTERVAL);
+}
+
 }  // namespace
 
-// TODO(primiano): this should be smarter and should do something similar to
-// trace event synthetic delays.
-const char MemoryDumpManager::kTraceCategory[] =
-    TRACE_DISABLED_BY_DEFAULT("memory-dumps");
+// static
+const char* const MemoryDumpManager::kTraceCategoryForTesting = kTraceCategory;
 
 // static
 MemoryDumpManager* MemoryDumpManager::GetInstance() {
@@ -56,11 +138,17 @@
 
 // static
 void MemoryDumpManager::SetInstanceForTesting(MemoryDumpManager* instance) {
+  if (instance)
+    instance->skip_core_dumpers_auto_registration_for_testing_ = true;
   g_instance_for_testing = instance;
 }
 
 MemoryDumpManager::MemoryDumpManager()
-    : dump_provider_currently_active_(nullptr), memory_tracing_enabled_(0) {
+    : dump_provider_currently_active_(nullptr),
+      delegate_(nullptr),
+      memory_tracing_enabled_(0),
+      skip_core_dumpers_auto_registration_for_testing_(false) {
+  g_next_guid.GetNext();  // Make sure that first guid is not zero.
 }
 
 MemoryDumpManager::~MemoryDumpManager() {
@@ -70,94 +158,176 @@
 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;
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  // Enable the core dump providers.
+  RegisterDumpProvider(ProcessMemoryTotalsDumpProvider::GetInstance());
+  RegisterDumpProvider(ProcessMemoryMapsDumpProvider::GetInstance());
+  RegisterDumpProvider(MallocDumpProvider::GetInstance());
+#elif defined(OS_WIN)
+  RegisterDumpProvider(WinHeapDumpProvider::GetInstance());
+#endif
+}
+
+void MemoryDumpManager::SetDelegate(MemoryDumpManagerDelegate* delegate) {
+  AutoLock lock(lock_);
+  DCHECK_EQ(static_cast<MemoryDumpManagerDelegate*>(nullptr), delegate_);
+  delegate_ = delegate;
 }
 
 void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider* mdp) {
   AutoLock lock(lock_);
-  if (std::find(dump_providers_registered_.begin(),
-                dump_providers_registered_.end(),
-                mdp) != dump_providers_registered_.end()) {
-    return;
-  }
-  dump_providers_registered_.push_back(mdp);
+  dump_providers_registered_.insert(mdp);
 }
 
 void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) {
   AutoLock lock(lock_);
 
-  // Remove from the registered providers list.
-  auto it = std::find(dump_providers_registered_.begin(),
-                      dump_providers_registered_.end(), mdp);
-  if (it != dump_providers_registered_.end())
-    dump_providers_registered_.erase(it);
+  // Unregistration of a MemoryDumpProvider while tracing is ongoing is safe
+  // only if the MDP has specified a thread affinity (via task_runner()) AND
+  // the unregistration happens on the same thread (so the MDP cannot unregister
+  // and DumpInto() at the same time).
+  // Otherwise, it is not possible to guarantee that its unregistration is
+  // race-free. If you hit this DCHECK, your MDP has a bug.
+  DCHECK_IMPLIES(
+      subtle::NoBarrier_Load(&memory_tracing_enabled_),
+      mdp->task_runner() && mdp->task_runner()->BelongsToCurrentThread())
+      << "The MemoryDumpProvider " << mdp->GetFriendlyName() << " attempted to "
+      << "unregister itself in a racy way. Please file a crbug.";
 
   // Remove from the enabled providers list. This is to deal with the case that
   // UnregisterDumpProvider is called while the trace is enabled.
-  it = std::find(dump_providers_enabled_.begin(), dump_providers_enabled_.end(),
-                 mdp);
-  if (it != dump_providers_enabled_.end())
-    dump_providers_enabled_.erase(it);
+  dump_providers_enabled_.erase(mdp);
+  dump_providers_registered_.erase(mdp);
 }
 
-void MemoryDumpManager::RequestDumpPoint(DumpPointType dump_point_type) {
-  // TODO(primiano): this will have more logic to coordinate dump points across
-  // multiple processes via IPC. See crbug.com/462930.
-
+void MemoryDumpManager::RequestGlobalDump(
+    MemoryDumpType dump_type,
+    const MemoryDumpCallback& callback) {
   // Bail out immediately if tracing is not enabled at all.
   if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_)))
     return;
 
-  // TODO(primiano): Make guid actually unique (cross-process) by hashing it
-  // with the PID. See crbug.com/462931 for details.
-  const uint64 guid = g_next_guid.GetNext();
-  CreateLocalDumpPoint(dump_point_type, guid);
-}
+  const uint64 guid =
+      TraceLog::GetInstance()->MangleEventId(g_next_guid.GetNext());
 
-void MemoryDumpManager::BroadcastDumpRequest() {
-  NOTREACHED();  // TODO(primiano): implement IPC synchronization.
-}
-
-// Creates a dump point for the current process and appends it to the trace.
-void MemoryDumpManager::CreateLocalDumpPoint(DumpPointType dump_point_type,
-                                             uint64 guid) {
-  bool did_any_provider_dump = false;
-  scoped_ptr<ProcessMemoryDump> pmd(new ProcessMemoryDump());
-
-  // Serialize dump point generation so that memory dump providers don't have to
-  // deal with thread safety.
+  // 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.
+  MemoryDumpManagerDelegate* delegate;
   {
     AutoLock lock(lock_);
-    for (auto it = dump_providers_enabled_.begin();
-         it != dump_providers_enabled_.end();) {
-      dump_provider_currently_active_ = *it;
-      if (dump_provider_currently_active_->DumpInto(pmd.get())) {
-        did_any_provider_dump = true;
-        ++it;
-      } else {
-        LOG(ERROR) << "The memory dumper "
-                   << dump_provider_currently_active_->GetFriendlyName()
-                   << " failed, possibly due to sandboxing (crbug.com/461788), "
-                      "disabling it for current process. Try restarting chrome "
-                      "with the --no-sandbox switch.";
-        it = dump_providers_enabled_.erase(it);
-      }
-      dump_provider_currently_active_ = nullptr;
-    }
+    delegate = delegate_;
   }
 
-  // Don't create a dump point if all the dumpers failed.
-  if (!did_any_provider_dump)
-    return;
+  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};
+    delegate->RequestGlobalMemoryDump(args, callback);
+  } else if (!callback.is_null()) {
+    callback.Run(guid, false /* success */);
+  }
+}
 
-  scoped_refptr<ConvertableToTraceFormat> event_value(new TracedValue());
-  pmd->AsValueInto(static_cast<TracedValue*>(event_value.get()));
-  const char* const event_name = DumpPointTypeToString(dump_point_type);
+void MemoryDumpManager::RequestGlobalDump(MemoryDumpType dump_type) {
+  RequestGlobalDump(dump_type, MemoryDumpCallback());
+}
 
-  TRACE_EVENT_API_ADD_TRACE_EVENT(
-      TRACE_EVENT_PHASE_MEMORY_DUMP,
-      TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name, guid,
-      kTraceEventNumArgs, kTraceEventArgNames, kTraceEventArgTypes,
-      NULL /* arg_values */, &event_value, TRACE_EVENT_FLAG_HAS_ID);
+// Creates a memory dump for the current process and appends it to the trace.
+void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args,
+                                          const MemoryDumpCallback& callback) {
+  scoped_refptr<ProcessMemoryDumpHolder> pmd_holder(
+      new ProcessMemoryDumpHolder(args, session_state_, callback));
+  ProcessMemoryDump* pmd = &pmd_holder->process_memory_dump;
+  bool did_any_provider_dump = false;
+
+  // Iterate over the active dump providers and invoke DumpInto(pmd).
+  // The MDM guarantees linearity (at most one MDP is active within one
+  // process) and thread-safety (MDM enforces the right locking when entering /
+  // leaving the MDP.DumpInto() call). This is to simplify the clients' design
+  // and not let the MDPs worry about locking.
+  // As regards thread affinity, depending on the MDP configuration (see
+  // memory_dump_provider.h), the DumpInto() invocation can happen:
+  //  - Synchronousy on the MDM thread, when MDP.task_runner() is not set.
+  //  - Posted on MDP.task_runner(), when MDP.task_runner() is set.
+  {
+    AutoLock lock(lock_);
+    for (auto dump_provider_iter = dump_providers_enabled_.begin();
+         dump_provider_iter != dump_providers_enabled_.end();) {
+      // InvokeDumpProviderLocked will remove the MDP from the set if it fails.
+      MemoryDumpProvider* mdp = *dump_provider_iter;
+      ++dump_provider_iter;
+      if (mdp->task_runner()) {
+        // The DumpInto() call must be posted.
+        bool did_post_async_task = mdp->task_runner()->PostTask(
+            FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump,
+                            Unretained(this), Unretained(mdp), pmd_holder));
+        // The thread underlying the TaskRunner might have gone away.
+        if (did_post_async_task)
+          ++pmd_holder->num_pending_async_requests;
+      } else {
+        // Invoke the dump provider synchronously.
+        did_any_provider_dump |= InvokeDumpProviderLocked(mdp, pmd);
+      }
+    }
+  }  // AutoLock
+
+  // If at least one synchronous provider did dump and there are no pending
+  // asynchronous requests, add the dump to the trace and invoke the callback
+  // straight away (FinalizeDumpAndAddToTrace() takes care of the callback).
+  if (did_any_provider_dump && pmd_holder->num_pending_async_requests == 0)
+    FinalizeDumpAndAddToTrace(pmd_holder);
+}
+
+// Invokes the MemoryDumpProvider.DumpInto(), taking care of the failsafe logic
+// which disables the dumper when failing (crbug.com/461788).
+bool MemoryDumpManager::InvokeDumpProviderLocked(MemoryDumpProvider* mdp,
+                                                 ProcessMemoryDump* pmd) {
+  lock_.AssertAcquired();
+  dump_provider_currently_active_ = mdp;
+  bool dump_successful = mdp->DumpInto(pmd);
+  dump_provider_currently_active_ = nullptr;
+  if (!dump_successful) {
+    LOG(ERROR) << "The memory dumper " << mdp->GetFriendlyName()
+               << " failed, possibly due to sandboxing (crbug.com/461788), "
+                  "disabling it for current process. Try restarting chrome "
+                  "with the --no-sandbox switch.";
+    dump_providers_enabled_.erase(mdp);
+  }
+  return dump_successful;
+}
+
+// This is posted to arbitrary threads as a continuation of CreateProcessDump(),
+// when one or more MemoryDumpProvider(s) require the DumpInto() call to happen
+// on a different thread.
+void MemoryDumpManager::ContinueAsyncProcessDump(
+    MemoryDumpProvider* mdp,
+    scoped_refptr<ProcessMemoryDumpHolder> pmd_holder) {
+  bool should_finalize_dump = false;
+  {
+    // The lock here is to guarantee that different asynchronous dumps on
+    // different threads are still serialized, so that the MemoryDumpProvider
+    // has a consistent view of the |pmd| argument passed.
+    AutoLock lock(lock_);
+    ProcessMemoryDump* pmd = &pmd_holder->process_memory_dump;
+
+    // Check if the MemoryDumpProvider is still there. It might have been
+    // destroyed and unregistered while hopping threads.
+    if (dump_providers_enabled_.count(mdp))
+      InvokeDumpProviderLocked(mdp, pmd);
+
+    // Finalize the dump appending it to the trace if this was the last
+    // asynchronous request pending.
+    --pmd_holder->num_pending_async_requests;
+    if (pmd_holder->num_pending_async_requests == 0)
+      should_finalize_dump = true;
+  }  // AutoLock(lock_)
+
+  if (should_finalize_dump)
+    FinalizeDumpAndAddToTrace(pmd_holder);
 }
 
 void MemoryDumpManager::OnTraceLogEnabled() {
@@ -168,19 +338,36 @@
   TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled);
 
   AutoLock lock(lock_);
-  if (enabled) {
-    dump_providers_enabled_.assign(dump_providers_registered_.begin(),
-                                   dump_providers_registered_.end());
-  } else {
+
+  // There is no point starting the tracing without a delegate.
+  if (!enabled || !delegate_) {
     dump_providers_enabled_.clear();
+    return;
   }
+
+  // Merge the dictionary of allocator attributes from all dump providers
+  // into the session state.
+  session_state_ = new MemoryDumpSessionState();
+  for (const MemoryDumpProvider* mdp : dump_providers_registered_) {
+    session_state_->allocators_attributes_type_info.Update(
+        mdp->allocator_attributes_type_info());
+  }
+  dump_providers_enabled_ = dump_providers_registered_;
   subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);
+
+  if (delegate_->IsCoordinatorProcess()) {
+    periodic_dump_timer_.Start(FROM_HERE,
+                               TimeDelta::FromSeconds(kDumpIntervalSeconds),
+                               base::Bind(&RequestPeriodicGlobalDump));
+  }
 }
 
 void MemoryDumpManager::OnTraceLogDisabled() {
   AutoLock lock(lock_);
+  periodic_dump_timer_.Stop();
   dump_providers_enabled_.clear();
   subtle::NoBarrier_Store(&memory_tracing_enabled_, 0);
+  session_state_ = nullptr;
 }
 
 }  // namespace trace_event
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h
index 04d0135..371a47a 100644
--- a/base/trace_event/memory_dump_manager.h
+++ b/base/trace_event/memory_dump_manager.h
@@ -8,42 +8,58 @@
 #include <vector>
 
 #include "base/atomicops.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/singleton.h"
 #include "base/synchronization/lock.h"
+#include "base/timer/timer.h"
+#include "base/trace_event/memory_dump_request_args.h"
 #include "base/trace_event/trace_event.h"
 
 namespace base {
 namespace trace_event {
 
-class MemoryDumpProvider;
+namespace {
+class ProcessMemoryDumpHolder;
+}
 
-// Captures the reason why a dump point is being requested. This is to allow
-// selective enabling of dump points, filtering and post-processing.
-enum class DumpPointType {
-  TASK_BEGIN,         // Dumping memory at the beginning of a message-loop task.
-  TASK_END,           // Dumping memory at the ending of a message-loop task.
-  PERIODIC_INTERVAL,  // Dumping memory at periodic intervals.
-  EXPLICITLY_TRIGGERED,  // Non maskable dump request.
-};
+class MemoryDumpManagerDelegate;
+class MemoryDumpProvider;
+class ProcessMemoryDump;
+class MemoryDumpSessionState;
 
 // This is the interface exposed to the rest of the codebase to deal with
 // memory tracing. The main entry point for clients is represented by
 // RequestDumpPoint(). The extension by Un(RegisterDumpProvider).
 class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
  public:
+  static const char* const kTraceCategoryForTesting;
+
   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);
+
   // MemoryDumpManager does NOT take memory ownership of |mdp|, which is
-  // expected to be a singleton.
+  // expected to either be a singleton or unregister itself.
   void RegisterDumpProvider(MemoryDumpProvider* mdp);
   void UnregisterDumpProvider(MemoryDumpProvider* mdp);
 
   // Requests a memory dump. The dump might happen or not depending on the
   // filters and categories specified when enabling tracing.
-  void RequestDumpPoint(DumpPointType dump_point_type);
+  // 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 MemoryDumpCallback& callback);
+
+  // Same as above (still asynchronous), but without callback.
+  void RequestGlobalDump(MemoryDumpType dump_type);
 
   // TraceLog::EnabledStateObserver implementation.
   void OnTraceLogEnabled() override;
@@ -55,41 +71,89 @@
     return dump_provider_currently_active_;
   }
 
+  // Returns the MemoryDumpSessionState object, which is shared by all the
+  // ProcessMemoryDump and MemoryAllocatorDump instances through all the tracing
+  // session lifetime.
+  const scoped_refptr<MemoryDumpSessionState>& session_state() const {
+    return session_state_;
+  }
+
  private:
   friend struct DefaultDeleter<MemoryDumpManager>;  // For the testing instance.
   friend struct DefaultSingletonTraits<MemoryDumpManager>;
+  friend class MemoryDumpManagerDelegate;
   friend class MemoryDumpManagerTest;
 
-  static const char kTraceCategory[];
-
   static void SetInstanceForTesting(MemoryDumpManager* instance);
 
   MemoryDumpManager();
   virtual ~MemoryDumpManager();
 
-  // Broadcasts the dump requests to the other processes.
-  void BroadcastDumpRequest();
+  // Internal, used only by MemoryDumpManagerDelegate.
+  // Creates a memory dump for the current process and appends it to the trace.
+  // |callback| will be invoked asynchronously upon completion on the same
+  // thread on which CreateProcessDump() was called.
+  void CreateProcessDump(const MemoryDumpRequestArgs& args,
+                         const MemoryDumpCallback& callback);
 
-  // Creates a dump point for the current process and appends it to the trace.
-  void CreateLocalDumpPoint(DumpPointType dump_point_type, uint64 guid);
+  bool InvokeDumpProviderLocked(MemoryDumpProvider* mdp,
+                                ProcessMemoryDump* pmd);
+  void ContinueAsyncProcessDump(
+      MemoryDumpProvider* mdp,
+      scoped_refptr<ProcessMemoryDumpHolder> pmd_holder);
 
-  std::vector<MemoryDumpProvider*> dump_providers_registered_;  // Not owned.
-  std::vector<MemoryDumpProvider*> dump_providers_enabled_;     // Not owned.
+  hash_set<MemoryDumpProvider*> dump_providers_registered_;  // Not owned.
+  hash_set<MemoryDumpProvider*> dump_providers_enabled_;     // Not owned.
 
   // TODO(primiano): this is required only until crbug.com/466121 gets fixed.
-  MemoryDumpProvider* dump_provider_currently_active_;  // Now owned.
+  MemoryDumpProvider* dump_provider_currently_active_;  // Not owned.
 
-  // Protects from concurrent accesses to the |dump_providers_*|, e.g., tearing
-  // down logging while creating a dump point on another thread.
+  // Shared among all the PMDs to keep state scoped to the tracing session.
+  scoped_refptr<MemoryDumpSessionState> session_state_;
+
+  MemoryDumpManagerDelegate* delegate_;  // Not owned.
+
+  // Protects from concurrent accesses to the |dump_providers_*| and |delegate_|
+  // to guard against disabling logging while dumping on another thread.
   Lock lock_;
 
-  // Optimization to avoid attempting any dump point (i.e. to not walk an empty
+  // Optimization to avoid attempting any memory dump (i.e. to not walk an empty
   // dump_providers_enabled_ list) when tracing is not enabled.
   subtle::AtomicWord memory_tracing_enabled_;
 
+  // For time-triggered periodic dumps.
+  RepeatingTimer<MemoryDumpManager> periodic_dump_timer_;
+
+  // Skips the auto-registration of the core dumpers during Initialize().
+  bool skip_core_dumpers_auto_registration_for_testing_;
+
   DISALLOW_COPY_AND_ASSIGN(MemoryDumpManager);
 };
 
+// The delegate is supposed to be long lived (read: a Singleton) and thread
+// safe (i.e. should expect calls from any thread and handle thread hopping).
+class BASE_EXPORT MemoryDumpManagerDelegate {
+ public:
+  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;
+
+ protected:
+  MemoryDumpManagerDelegate() {}
+  virtual ~MemoryDumpManagerDelegate() {}
+
+  void CreateProcessDump(const MemoryDumpRequestArgs& args,
+                         const MemoryDumpCallback& callback) {
+    MemoryDumpManager::GetInstance()->CreateProcessDump(args, callback);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MemoryDumpManagerDelegate);
+};
+
 }  // namespace trace_event
 }  // namespace base
 
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
index 65e719f..589c406 100644
--- a/base/trace_event/memory_dump_manager_unittest.cc
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -4,6 +4,11 @@
 
 #include "base/trace_event/memory_dump_manager.h"
 
+#include "base/bind_helpers.h"
+#include "base/memory/scoped_vector.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/threading/thread.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -16,23 +21,46 @@
 namespace base {
 namespace trace_event {
 
+// Testing MemoryDumpManagerDelegate which short-circuits dump requests locally
+// instead of performing IPC dances.
+class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate {
+ public:
+  void RequestGlobalMemoryDump(
+      const base::trace_event::MemoryDumpRequestArgs& args,
+      const MemoryDumpCallback& callback) override {
+    CreateProcessDump(args, callback);
+  }
+
+  bool IsCoordinatorProcess() const override { return false; }
+};
+
 class MemoryDumpManagerTest : public testing::Test {
  public:
   void SetUp() override {
+    message_loop_.reset(new MessageLoop());
     mdm_.reset(new MemoryDumpManager());
     MemoryDumpManager::SetInstanceForTesting(mdm_.get());
     ASSERT_EQ(mdm_, MemoryDumpManager::GetInstance());
     MemoryDumpManager::GetInstance()->Initialize();
+    MemoryDumpManager::GetInstance()->SetDelegate(&delegate_);
   }
 
   void TearDown() override {
     MemoryDumpManager::SetInstanceForTesting(nullptr);
     mdm_.reset();
+    message_loop_.reset();
     TraceLog::DeleteForTesting();
   }
 
+  void DumpCallbackAdapter(scoped_refptr<SingleThreadTaskRunner> task_runner,
+                           Closure closure,
+                           uint64 dump_guid,
+                           bool success) {
+    task_runner->PostTask(FROM_HERE, closure);
+  }
+
  protected:
-  const char* const kTraceCategory = MemoryDumpManager::kTraceCategory;
+  const char* kTraceCategory = MemoryDumpManager::kTraceCategoryForTesting;
 
   void EnableTracing(const char* category) {
     TraceLog::GetInstance()->SetEnabled(
@@ -44,15 +72,29 @@
   scoped_ptr<MemoryDumpManager> mdm_;
 
  private:
+  scoped_ptr<MessageLoop> message_loop_;
+  MemoryDumpManagerDelegateForTesting delegate_;
+
   // We want our singleton torn down after each test.
   ShadowingAtExitManager at_exit_manager_;
 };
 
 class MockDumpProvider : public MemoryDumpProvider {
  public:
+  MockDumpProvider() {}
+
+  explicit MockDumpProvider(
+      const scoped_refptr<SingleThreadTaskRunner>& task_runner)
+      : MemoryDumpProvider(task_runner) {}
+
+  // Ctor for the SharedSessionState test.
+  explicit MockDumpProvider(const std::string& id) {
+    DeclareAllocatorAttribute("allocator" + id, "attr" + id, "type" + id);
+  }
+
   MOCK_METHOD1(DumpInto, bool(ProcessMemoryDump* pmd));
 
-  // DumpInto() override for the ActiveDumpProviderConsistency test,
+  // DumpInto() override for the ActiveDumpProviderConsistency test.
   bool DumpIntoAndCheckDumpProviderCurrentlyActive(ProcessMemoryDump* pmd) {
     EXPECT_EQ(
         this,
@@ -60,6 +102,22 @@
     return true;
   }
 
+  // DumpInto() override for the RespectTaskRunnerAffinity test.
+  bool DumpIntoAndCheckTaskRunner(ProcessMemoryDump* pmd) {
+    EXPECT_TRUE(task_runner()->RunsTasksOnCurrentThread());
+    return true;
+  }
+
+  // DumpInto() override for the SharedSessionState test.
+  bool DumpIntoAndCheckSessionState(ProcessMemoryDump* pmd) {
+    EXPECT_TRUE(pmd->session_state());
+    const auto& attrs_type_info =
+        pmd->session_state()->allocators_attributes_type_info;
+    EXPECT_TRUE(attrs_type_info.Exists("allocator1", "attr1"));
+    EXPECT_TRUE(attrs_type_info.Exists("allocator2", "attr2"));
+    return true;
+  }
+
   const char* GetFriendlyName() const override { return "MockDumpProvider"; }
 };
 
@@ -70,7 +128,7 @@
   // Check that the dumper is not called if the memory category is not enabled.
   EnableTracing("foo-and-bar-but-not-memory");
   EXPECT_CALL(mdp, DumpInto(_)).Times(0);
-  mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
   DisableTracing();
 
   // Now repeat enabling the memory category and check that the dumper is
@@ -78,7 +136,7 @@
   EnableTracing(kTraceCategory);
   EXPECT_CALL(mdp, DumpInto(_)).Times(3).WillRepeatedly(Return(true));
   for (int i = 0; i < 3; ++i)
-    mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+    mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
   DisableTracing();
 
   mdm_->UnregisterDumpProvider(&mdp);
@@ -86,21 +144,24 @@
   // Finally check the unregister logic (no calls to the mdp after unregister).
   EnableTracing(kTraceCategory);
   EXPECT_CALL(mdp, DumpInto(_)).Times(0);
-  mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
   TraceLog::GetInstance()->SetDisabled();
 }
 
-TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileTracing) {
-  MockDumpProvider mdp;
-  mdm_->RegisterDumpProvider(&mdp);
+TEST_F(MemoryDumpManagerTest, SharedSessionState) {
+  MockDumpProvider mdp1("1");  // Will declare an allocator property "attr1".
+  MockDumpProvider mdp2("2");  // Will declare an allocator property "attr2".
+  mdm_->RegisterDumpProvider(&mdp1);
+  mdm_->RegisterDumpProvider(&mdp2);
 
   EnableTracing(kTraceCategory);
-  EXPECT_CALL(mdp, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
-  mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+  EXPECT_CALL(mdp1, DumpInto(_)).Times(2).WillRepeatedly(
+      Invoke(&mdp1, &MockDumpProvider::DumpIntoAndCheckSessionState));
+  EXPECT_CALL(mdp2, DumpInto(_)).Times(2).WillRepeatedly(
+      Invoke(&mdp2, &MockDumpProvider::DumpIntoAndCheckSessionState));
 
-  mdm_->UnregisterDumpProvider(&mdp);
-  EXPECT_CALL(mdp, DumpInto(_)).Times(0);
-  mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+  for (int i = 0; i < 2; ++i)
+    mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
 
   DisableTracing();
 }
@@ -114,7 +175,7 @@
   EnableTracing(kTraceCategory);
   EXPECT_CALL(mdp1, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
   EXPECT_CALL(mdp2, DumpInto(_)).Times(0);
-  mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
   DisableTracing();
 
   // Invert: enable mdp1 and disable mdp2.
@@ -123,7 +184,7 @@
   EnableTracing(kTraceCategory);
   EXPECT_CALL(mdp1, DumpInto(_)).Times(0);
   EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
-  mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
   DisableTracing();
 
   // Enable both mdp1 and mdp2.
@@ -131,7 +192,66 @@
   EnableTracing(kTraceCategory);
   EXPECT_CALL(mdp1, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
   EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
-  mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  DisableTracing();
+}
+
+// Checks that the MemoryDumpManager respects the thread affinity when a
+// MemoryDumpProvider specifies a task_runner(). The test starts creating 8
+// 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) {
+  const uint32 kNumInitialThreads = 8;
+
+  ScopedVector<Thread> threads;
+  ScopedVector<MockDumpProvider> 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"));
+    threads.back()->Start();
+    mdps.push_back(new MockDumpProvider(threads.back()->task_runner()));
+    MockDumpProvider* mdp = mdps.back();
+    mdm_->RegisterDumpProvider(mdp);
+    EXPECT_CALL(*mdp, DumpInto(_))
+        .Times(i)
+        .WillRepeatedly(
+            Invoke(mdp, &MockDumpProvider::DumpIntoAndCheckTaskRunner));
+  }
+
+  EnableTracing(kTraceCategory);
+
+  while (!threads.empty()) {
+    {
+      RunLoop run_loop;
+      MemoryDumpCallback callback =
+          Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
+               MessageLoop::current()->task_runner(), run_loop.QuitClosure());
+      mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, callback);
+      // This nested message loop (|run_loop|) will be quit if and only if
+      // the RequestGlobalDump callback is invoked.
+      run_loop.Run();
+    }
+
+    // Unregister a MDP and destroy one thread at each iteration to check the
+    // live unregistration logic. The unregistration needs to happen on the same
+    // thread the MDP belongs to.
+    {
+      RunLoop run_loop;
+      Closure unregistration =
+          Bind(&MemoryDumpManager::UnregisterDumpProvider,
+               Unretained(mdm_.get()), Unretained(mdps.back()));
+      threads.back()->task_runner()->PostTaskAndReply(FROM_HERE, unregistration,
+                                                      run_loop.QuitClosure());
+      run_loop.Run();
+    }
+    mdps.pop_back();
+    threads.back()->Stop();
+    threads.pop_back();
+  }
+
   DisableTracing();
 }
 
@@ -148,11 +268,11 @@
 
   EXPECT_CALL(mdp1, DumpInto(_)).Times(1).WillRepeatedly(Return(false));
   EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
-  mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
 
   EXPECT_CALL(mdp1, DumpInto(_)).Times(0);
   EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(false));
-  mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
 
   DisableTracing();
 }
@@ -177,8 +297,8 @@
       .WillRepeatedly(Invoke(
           &mdp2,
           &MockDumpProvider::DumpIntoAndCheckDumpProviderCurrentlyActive));
-  mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
-  mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
   DisableTracing();
 }
 
diff --git a/base/trace_event/memory_dump_provider.cc b/base/trace_event/memory_dump_provider.cc
index 9518461..a2d3889 100644
--- a/base/trace_event/memory_dump_provider.cc
+++ b/base/trace_event/memory_dump_provider.cc
@@ -4,7 +4,7 @@
 
 #include "base/trace_event/memory_dump_provider.h"
 
-#include "base/logging.h"
+#include "base/single_thread_task_runner.h"
 
 namespace base {
 namespace trace_event {
@@ -12,15 +12,20 @@
 MemoryDumpProvider::MemoryDumpProvider() {
 }
 
+MemoryDumpProvider::MemoryDumpProvider(
+    const scoped_refptr<SingleThreadTaskRunner>& task_runner)
+    : task_runner_(task_runner) {
+}
+
 MemoryDumpProvider::~MemoryDumpProvider() {
 }
 
 void MemoryDumpProvider::DeclareAllocatorAttribute(
-    const MemoryAllocatorDeclaredAttribute& attr) {
-  DCHECK_EQ(0u, allocator_attributes_.count(attr.name))
-      << "Allocator attribute " << attr.name << " already declared for dumper "
-      << GetFriendlyName();
-  allocator_attributes_[attr.name] = attr;
+    const std::string& allocator_name,
+    const std::string& attribute_name,
+    const std::string& attribute_type) {
+  allocator_attributes_type_info_.Set(
+      allocator_name, attribute_name, attribute_type);
 }
 
 }  // namespace trace_event
diff --git a/base/trace_event/memory_dump_provider.h b/base/trace_event/memory_dump_provider.h
index 5cc3a6e..9ec7ad9 100644
--- a/base/trace_event/memory_dump_provider.h
+++ b/base/trace_event/memory_dump_provider.h
@@ -6,9 +6,13 @@
 #define BASE_TRACE_EVENT_MEMORY_DUMP_PROVIDER_H_
 
 #include "base/base_export.h"
-#include "base/trace_event/memory_allocator_attributes.h"
+#include "base/memory/ref_counted.h"
+#include "base/trace_event/memory_allocator_attributes_type_info.h"
 
 namespace base {
+
+class SingleThreadTaskRunner;
+
 namespace trace_event {
 
 class ProcessMemoryDump;
@@ -16,27 +20,46 @@
 // The contract interface that memory dump providers must implement.
 class BASE_EXPORT MemoryDumpProvider {
  public:
-  // Called by the MemoryDumpManager when generating dump points.
+  // Called by the MemoryDumpManager when generating memory dumps.
   // Returns: true if the |pmd| was successfully populated, false otherwise.
   virtual bool DumpInto(ProcessMemoryDump* pmd) = 0;
 
   virtual const char* GetFriendlyName() const = 0;
 
-  const MemoryAllocatorDeclaredAttributes& allocator_attributes() const {
-    return allocator_attributes_;
+  const MemoryAllocatorAttributesTypeInfo& allocator_attributes_type_info()
+      const {
+    return allocator_attributes_type_info_;
+  }
+
+  // The dump provider can specify an optional thread affinity (in its
+  // base constructor call). If |task_runner| is non empty, all the calls to
+  // DumpInto are guaranteed to be posted to that TaskRunner.
+  const scoped_refptr<SingleThreadTaskRunner>& task_runner() const {
+    return task_runner_;
   }
 
  protected:
+  // Default ctor: the MDP is not bound to any thread (must be a singleton).
   MemoryDumpProvider();
+
+  // Use this ctor to ensure that DumpInto() is called always on the same thread
+  // specified by |task_runner|.
+  explicit MemoryDumpProvider(
+      const scoped_refptr<SingleThreadTaskRunner>& task_runner);
+
   virtual ~MemoryDumpProvider();
 
-  void DeclareAllocatorAttribute(const MemoryAllocatorDeclaredAttribute& attr);
+  void DeclareAllocatorAttribute(const std::string& allocator_name,
+                                 const std::string& attribute_name,
+                                 const std::string& attribute_type);
 
  private:
-  // The map (attribute name -> type) that specifies the semantic of the
-  // extra attributes that the MemoryAllocatorDump(s) produced by this
-  // MemoryDumpProvider will have.
-  MemoryAllocatorDeclaredAttributes allocator_attributes_;
+  // A map of attributes types (declared through DeclareAllocatorAttribute())
+  // emitted by this allocator dumper.
+  MemoryAllocatorAttributesTypeInfo allocator_attributes_type_info_;
+
+  // (Optional) TaskRunner on which the DumpInfo call should be posted.
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(MemoryDumpProvider);
 };
diff --git a/base/trace_event/memory_dump_request_args.h b/base/trace_event/memory_dump_request_args.h
new file mode 100644
index 0000000..4fb0335
--- /dev/null
+++ b/base/trace_event/memory_dump_request_args.h
@@ -0,0 +1,41 @@
+// 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_MEMORY_DUMP_REQUEST_H_
+#define BASE_TRACE_EVENT_MEMORY_DUMP_REQUEST_H_
+
+// 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 "base/base_export.h"
+#include "base/callback.h"
+
+namespace base {
+namespace trace_event {
+
+// Captures the reason why a memory dump is being requested. This is to allow
+// selective enabling of dumps, filtering and post-processing.
+enum class MemoryDumpType {
+  TASK_BEGIN,         // Dumping memory at the beginning of a message-loop task.
+  TASK_END,           // Dumping memory at the ending of a message-loop task.
+  PERIODIC_INTERVAL,  // Dumping memory at periodic intervals.
+  EXPLICITLY_TRIGGERED,  // Non maskable dump request.
+  LAST = EXPLICITLY_TRIGGERED // For IPC macros.
+};
+
+using MemoryDumpCallback = Callback<void(uint64 dump_guid, bool success)>;
+
+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
+  // reconstruct the global dump.
+  uint64 dump_guid;
+
+  MemoryDumpType dump_type;
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_DUMP_REQUEST_H_
diff --git a/base/trace_event/memory_dump_session_state.cc b/base/trace_event/memory_dump_session_state.cc
new file mode 100644
index 0000000..433ac14
--- /dev/null
+++ b/base/trace_event/memory_dump_session_state.cc
@@ -0,0 +1,17 @@
+// 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_session_state.h"
+
+namespace base {
+namespace trace_event {
+
+MemoryDumpSessionState::MemoryDumpSessionState() {
+}
+
+MemoryDumpSessionState::~MemoryDumpSessionState() {
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/memory_dump_session_state.h b/base/trace_event/memory_dump_session_state.h
new file mode 100644
index 0000000..38a6fe2
--- /dev/null
+++ b/base/trace_event/memory_dump_session_state.h
@@ -0,0 +1,31 @@
+// 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_MEMORY_DUMP_SESSION_STATE_H_
+#define BASE_TRACE_EVENT_MEMORY_DUMP_SESSION_STATE_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/memory/ref_counted.h"
+#include "base/trace_event/memory_allocator_attributes_type_info.h"
+
+namespace base {
+namespace trace_event {
+
+class BASE_EXPORT MemoryDumpSessionState
+    : public RefCountedThreadSafe<MemoryDumpSessionState> {
+ public:
+  MemoryDumpSessionState();
+  MemoryAllocatorAttributesTypeInfo allocators_attributes_type_info;
+
+ private:
+  friend class RefCountedThreadSafe<MemoryDumpSessionState>;
+  ~MemoryDumpSessionState();
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_DUMP_SESSION_STATE_H_
diff --git a/base/trace_event/process_memory_dump.cc b/base/trace_event/process_memory_dump.cc
index bbca36c..836d6ae 100644
--- a/base/trace_event/process_memory_dump.cc
+++ b/base/trace_event/process_memory_dump.cc
@@ -10,31 +10,32 @@
 namespace base {
 namespace trace_event {
 
-ProcessMemoryDump::ProcessMemoryDump()
-    : has_process_totals_(false), has_process_mmaps_(false) {
+ProcessMemoryDump::ProcessMemoryDump(
+    const scoped_refptr<MemoryDumpSessionState>& session_state)
+    : has_process_totals_(false),
+      has_process_mmaps_(false),
+      session_state_(session_state) {
 }
 
 ProcessMemoryDump::~ProcessMemoryDump() {
 }
 
 MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump(
-    const std::string& name) {
-  return CreateAllocatorDump(name, nullptr);
-}
-
-MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump(
-    const std::string& name,
-    MemoryAllocatorDump* parent) {
-  DCHECK_EQ(0ul, allocator_dumps_.count(name));
-  MemoryAllocatorDump* mad = new MemoryAllocatorDump(name, parent);
+    const std::string& allocator_name,
+    const std::string& heap_name) {
+  MemoryAllocatorDump* mad =
+      new MemoryAllocatorDump(allocator_name, heap_name, this);
+  DCHECK_EQ(0ul, allocator_dumps_.count(mad->GetAbsoluteName()));
   allocator_dumps_storage_.push_back(mad);
-  allocator_dumps_[name] = mad;
+  allocator_dumps_[mad->GetAbsoluteName()] = mad;
   return mad;
 }
 
 MemoryAllocatorDump* ProcessMemoryDump::GetAllocatorDump(
-    const std::string& name) const {
-  auto it = allocator_dumps_.find(name);
+    const std::string& allocator_name,
+    const std::string& heap_name) const {
+  auto it = allocator_dumps_.find(
+      MemoryAllocatorDump::GetAbsoluteName(allocator_name, heap_name));
   return it == allocator_dumps_.end() ? nullptr : it->second;
 }
 
diff --git a/base/trace_event/process_memory_dump.h b/base/trace_event/process_memory_dump.h
index df6cc82..bd9c543 100644
--- a/base/trace_event/process_memory_dump.h
+++ b/base/trace_event/process_memory_dump.h
@@ -8,8 +8,10 @@
 #include "base/base_export.h"
 #include "base/containers/hash_tables.h"
 #include "base/containers/small_map.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_vector.h"
 #include "base/trace_event/memory_allocator_dump.h"
+#include "base/trace_event/memory_dump_session_state.h"
 #include "base/trace_event/process_memory_maps.h"
 #include "base/trace_event/process_memory_totals.h"
 
@@ -18,19 +20,22 @@
 
 class ConvertableToTraceFormat;
 class MemoryDumpManager;
+class MemoryDumpSessionState;
 
 // ProcessMemoryDump is as a strongly typed container which enforces the data
-// model for each memory dump point and holds the dumps produced by the
+// 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.
 class BASE_EXPORT ProcessMemoryDump {
  public:
+  // Maps allocator dumps absolute names (allocator_name/heap/subheap) to
+  // MemoryAllocatorDump instances.
   using AllocatorDumpsMap =
       SmallMap<hash_map<std::string, MemoryAllocatorDump*>>;
 
-  ProcessMemoryDump();
+  ProcessMemoryDump(const scoped_refptr<MemoryDumpSessionState>& session_state);
   ~ProcessMemoryDump();
 
   // Called at trace generation time to populate the TracedValue.
@@ -45,20 +50,34 @@
   void set_has_process_mmaps() { has_process_mmaps_ = true; }
 
   // Creates a new MemoryAllocatorDump with the given name and returns the
-  // empty object back to the caller. The |name| must be unique in the dump.
-  // ProcessMemoryDump handles the memory ownership of the created object.
-  // |parent| can be used to specify a hierarchical relationship of the
-  // allocator dumps.
-  MemoryAllocatorDump* CreateAllocatorDump(const std::string& name);
-  MemoryAllocatorDump* CreateAllocatorDump(const std::string& name,
-                                           MemoryAllocatorDump* parent);
+  // empty object back to the caller.
+  // Arguments:
+  //   allocator_name: a name that univocally identifies allocator dumps
+  //     produced by this provider. It acts as a type w.r.t. the allocator
+  //     attributes, in the sense that all the MAD with the same allocator_name
+  //     are expected to have the same attributes.
+  //   heap_name, either:
+  //     - kRootHeap: if the allocator has only one default heap.
+  //     - a string identifing a heap name (e.g., isolate1, isolate2 ...). It is
+  //       possible to specify nesting by using a path-like string (e.g.,
+  //       isolate1/heap_spaceX, isolate1/heap_spaceY, isolate2/heap_spaceX).
+  // The tuple (|allocator_name|, |heap_name|) is unique inside a PMD.
+  // ProcessMemoryDump handles the memory ownership of its MemoryAllocatorDumps.
+  MemoryAllocatorDump* CreateAllocatorDump(const std::string& allocator_name,
+                                           const std::string& heap_name);
 
-  // Returns a MemoryAllocatorDump given its name or nullptr if not found.
-  MemoryAllocatorDump* GetAllocatorDump(const std::string& name) const;
+  // Looks up a MemoryAllocatorDump given its allocator and heap names, or
+  // nullptr if not found.
+  MemoryAllocatorDump* GetAllocatorDump(const std::string& allocator_name,
+                                        const std::string& heap_name) const;
 
   // Returns the map of the MemoryAllocatorDumps added to this dump.
   const AllocatorDumpsMap& allocator_dumps() const { return allocator_dumps_; }
 
+  const scoped_refptr<MemoryDumpSessionState>& session_state() const {
+    return session_state_;
+  }
+
  private:
   ProcessMemoryTotals process_totals_;
   bool has_process_totals_;
@@ -66,13 +85,14 @@
   ProcessMemoryMaps process_mmaps_;
   bool has_process_mmaps_;
 
-  // A maps of "allocator_name" -> MemoryAllocatorDump populated by
-  // allocator dump providers.
   AllocatorDumpsMap allocator_dumps_;
 
   // ProcessMemoryDump handles the memory ownership of all its belongings.
   ScopedVector<MemoryAllocatorDump> allocator_dumps_storage_;
 
+  // State shared among all PMDs instances created in a given trace session.
+  scoped_refptr<MemoryDumpSessionState> session_state_;
+
   DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDump);
 };
 
diff --git a/base/trace_event/process_memory_maps_dump_provider_unittest.cc b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
index 0bf81ac..2ce2504 100644
--- a/base/trace_event/process_memory_maps_dump_provider_unittest.cc
+++ b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
@@ -114,7 +114,7 @@
   auto pmmdp = ProcessMemoryMapsDumpProvider::GetInstance();
 
   // Emulate a non-existent /proc/self/smaps.
-  ProcessMemoryDump pmd_invalid;
+  ProcessMemoryDump pmd_invalid(nullptr /* session_state */);
   std::ifstream non_existent_file("/tmp/does-not-exist");
   ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &non_existent_file;
   CHECK_EQ(false, non_existent_file.good());
@@ -129,7 +129,7 @@
   ASSERT_FALSE(pmd_invalid.has_process_mmaps());
 
   // Parse the 1st smaps file.
-  ProcessMemoryDump pmd_1;
+  ProcessMemoryDump pmd_1(nullptr /* session_state */);
   std::istringstream test_smaps_1(kTestSmaps1);
   ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &test_smaps_1;
   pmmdp->DumpInto(&pmd_1);
@@ -154,7 +154,7 @@
   EXPECT_EQ((60 + 8) * 1024UL, regions_1[1].byte_stats_private_resident);
 
   // Parse the 2nd smaps file.
-  ProcessMemoryDump pmd_2;
+  ProcessMemoryDump pmd_2(nullptr /* session_state */);
   std::istringstream test_smaps_2(kTestSmaps2);
   ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &test_smaps_2;
   pmmdp->DumpInto(&pmd_2);
diff --git a/base/trace_event/process_memory_totals_dump_provider_unittest.cc b/base/trace_event/process_memory_totals_dump_provider_unittest.cc
index 372db63..ffaf177 100644
--- a/base/trace_event/process_memory_totals_dump_provider_unittest.cc
+++ b/base/trace_event/process_memory_totals_dump_provider_unittest.cc
@@ -13,8 +13,8 @@
 
 TEST(ProcessMemoryTotalsDumpProviderTest, DumpRSS) {
   auto pmtdp = ProcessMemoryTotalsDumpProvider::GetInstance();
-  scoped_ptr<ProcessMemoryDump> pmd_before(new ProcessMemoryDump());
-  scoped_ptr<ProcessMemoryDump> pmd_after(new ProcessMemoryDump());
+  scoped_ptr<ProcessMemoryDump> pmd_before(new ProcessMemoryDump(nullptr));
+  scoped_ptr<ProcessMemoryDump> pmd_after(new ProcessMemoryDump(nullptr));
 
   ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 1024;
   pmtdp->DumpInto(pmd_before.get());
diff --git a/base/trace_event/trace_event.gypi b/base/trace_event/trace_event.gypi
index ca6c076..9bbd172 100644
--- a/base/trace_event/trace_event.gypi
+++ b/base/trace_event/trace_event.gypi
@@ -4,13 +4,19 @@
 {
   'variables': {
     'trace_event_sources' : [
-      'trace_event/memory_allocator_attributes.h',
+      'trace_event/java_heap_dump_provider_android.cc',
+      'trace_event/java_heap_dump_provider_android.h',
+      'trace_event/memory_allocator_attributes_type_info.cc',
+      'trace_event/memory_allocator_attributes_type_info.h',
       'trace_event/memory_allocator_dump.cc',
       'trace_event/memory_allocator_dump.h',
       'trace_event/memory_dump_manager.cc',
       'trace_event/memory_dump_manager.h',
       'trace_event/memory_dump_provider.cc',
       'trace_event/memory_dump_provider.h',
+      'trace_event/memory_dump_request_args.h',
+      'trace_event/memory_dump_session_state.cc',
+      'trace_event/memory_dump_session_state.h',
       'trace_event/process_memory_dump.cc',
       'trace_event/process_memory_dump.h',
       'trace_event/process_memory_maps.cc',
@@ -25,6 +31,8 @@
       'trace_event/trace_event_android.cc',
       'trace_event/trace_event_argument.cc',
       'trace_event/trace_event_argument.h',
+      'trace_event/trace_event_etw_export_win.cc',
+      'trace_event/trace_event_etw_export_win.h',
       'trace_event/trace_event_impl.cc',
       'trace_event/trace_event_impl.h',
       'trace_event/trace_event_impl_constants.cc',
@@ -36,8 +44,19 @@
       'trace_event/trace_event_system_stats_monitor.h',
       'trace_event/trace_event_win.cc',
       'trace_event/trace_event_win.h',
+      'trace_event/winheap_dump_provider_win.cc',
+      'trace_event/winheap_dump_provider_win.h',
+    ],
+    'conditions': [
+      ['OS == "linux" or OS == "android"', {
+          'trace_event_sources': [
+            'trace_event/malloc_dump_provider.cc',
+            'trace_event/malloc_dump_provider.h',
+          ],
+      }],
     ],
     'trace_event_test_sources' : [
+      'trace_event/memory_allocator_attributes_type_info_unittest.cc',
       'trace_event/memory_allocator_dump_unittest.cc',
       'trace_event/memory_dump_manager_unittest.cc',
       'trace_event/process_memory_maps_dump_provider_unittest.cc',
@@ -48,6 +67,7 @@
       'trace_event/trace_event_system_stats_monitor_unittest.cc',
       'trace_event/trace_event_unittest.cc',
       'trace_event/trace_event_win_unittest.cc',
+      'trace_event/winheap_dump_provider_win_unittest.cc',
     ],
   },
 }
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
index 1bf9429..e0249f5 100644
--- a/base/trace_event/trace_event.h
+++ b/base/trace_event/trace_event.h
@@ -144,11 +144,11 @@
 //   class MyData : public base::trace_event::ConvertableToTraceFormat {
 //    public:
 //     MyData() {}
-//     virtual void AppendAsTraceFormat(std::string* out) const override {
+//     void AppendAsTraceFormat(std::string* out) const override {
 //       out->append("{\"foo\":1}");
 //     }
 //    private:
-//     virtual ~MyData() {}
+//     ~MyData() override {}
 //     DISALLOW_COPY_AND_ASSIGN(MyData);
 //   };
 //
@@ -601,6 +601,12 @@
         TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
         static_cast<int>(base::PlatformThread::CurrentId()), \
         timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, \
+        name, id, timestamp) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
+        static_cast<int>(base::PlatformThread::CurrentId()), \
+        timestamp, TRACE_EVENT_FLAG_COPY)
 
 // Records a single ASYNC_STEP_INTO event for |step| immediately. If the
 // category is not enabled, then this does nothing. The |name| and |id| must
@@ -828,9 +834,10 @@
         category_group, name, TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE)
 
 #define INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE() \
-    UNLIKELY(*INTERNAL_TRACE_EVENT_UID(category_group_enabled) & \
-        (base::trace_event::TraceLog::ENABLED_FOR_RECORDING | \
-         base::trace_event::TraceLog::ENABLED_FOR_EVENT_CALLBACK))
+  UNLIKELY(*INTERNAL_TRACE_EVENT_UID(category_group_enabled) &           \
+           (base::trace_event::TraceLog::ENABLED_FOR_RECORDING |         \
+            base::trace_event::TraceLog::ENABLED_FOR_EVENT_CALLBACK |    \
+            base::trace_event::TraceLog::ENABLED_FOR_ETW_EXPORT))
 
 // Macro to efficiently determine if a given category group is enabled.
 #define TRACE_EVENT_CATEGORY_GROUP_ENABLED(category_group, ret) \
diff --git a/base/trace_event/trace_event_etw_export_win.cc b/base/trace_event/trace_event_etw_export_win.cc
new file mode 100644
index 0000000..f7f9ecc
--- /dev/null
+++ b/base/trace_event/trace_event_etw_export_win.cc
@@ -0,0 +1,239 @@
+// 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/trace_event_etw_export_win.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_impl.h"
+
+// The GetProcAddress technique is borrowed from
+// https://github.com/randomascii/main/tree/master/xperf/ETWProviders
+//
+// EVNTAPI is used in evntprov.h which is included by chrome_events_win.h.
+// We define EVNTAPI without the DECLSPEC_IMPORT specifier so that we can
+// implement these functions locally instead of using the import library, and
+// can therefore still run on Windows XP.
+#define EVNTAPI __stdcall
+// Include the event register/write/unregister macros compiled from the manifest
+// file. Note that this includes evntprov.h which requires a Vista+ Windows SDK.
+//
+// In SHARED_INTERMEDIATE_DIR.
+#include "base/trace_event/etw_manifest/chrome_events_win.h"  // NOLINT
+
+namespace {
+// Typedefs for use with GetProcAddress
+typedef ULONG(__stdcall* tEventRegister)(LPCGUID ProviderId,
+                                         PENABLECALLBACK EnableCallback,
+                                         PVOID CallbackContext,
+                                         PREGHANDLE RegHandle);
+typedef ULONG(__stdcall* tEventWrite)(REGHANDLE RegHandle,
+                                      PCEVENT_DESCRIPTOR EventDescriptor,
+                                      ULONG UserDataCount,
+                                      PEVENT_DATA_DESCRIPTOR UserData);
+typedef ULONG(__stdcall* tEventUnregister)(REGHANDLE RegHandle);
+
+tEventRegister EventRegisterProc = nullptr;
+tEventWrite EventWriteProc = nullptr;
+tEventUnregister EventUnregisterProc = nullptr;
+}  // namespace
+
+// Redirector function for EventRegister. Called by macros in
+// chrome_events_win.h
+ULONG EVNTAPI EventRegister(LPCGUID ProviderId,
+                            PENABLECALLBACK EnableCallback,
+                            PVOID CallbackContext,
+                            PREGHANDLE RegHandle) {
+  if (EventRegisterProc)
+    return EventRegisterProc(ProviderId, EnableCallback, CallbackContext,
+                             RegHandle);
+  return 0;
+}
+
+// Redirector function for EventWrite. Called by macros in
+// chrome_events_win.h
+ULONG EVNTAPI EventWrite(REGHANDLE RegHandle,
+                         PCEVENT_DESCRIPTOR EventDescriptor,
+                         ULONG UserDataCount,
+                         PEVENT_DATA_DESCRIPTOR UserData) {
+  if (EventWriteProc)
+    return EventWriteProc(RegHandle, EventDescriptor, UserDataCount, UserData);
+  return 0;
+}
+
+// Redirector function for EventUnregister. Called by macros in
+// chrome_events_win.h
+ULONG EVNTAPI EventUnregister(REGHANDLE RegHandle) {
+  if (EventUnregisterProc)
+    return EventUnregisterProc(RegHandle);
+  return 0;
+}
+
+namespace base {
+namespace trace_event {
+
+TraceEventETWExport::TraceEventETWExport() : ETWExportEnabled_(false) {
+  // Find Advapi32.dll. This should always succeed.
+  HMODULE AdvapiDLL = ::LoadLibraryW(L"Advapi32.dll");
+  if (AdvapiDLL) {
+    // Try to find the ETW functions. This will fail on XP.
+    EventRegisterProc = reinterpret_cast<tEventRegister>(
+        ::GetProcAddress(AdvapiDLL, "EventRegister"));
+    EventWriteProc = reinterpret_cast<tEventWrite>(
+        ::GetProcAddress(AdvapiDLL, "EventWrite"));
+    EventUnregisterProc = reinterpret_cast<tEventUnregister>(
+        ::GetProcAddress(AdvapiDLL, "EventUnregister"));
+
+    // Register the ETW provider. If registration fails then the event logging
+    // calls will fail (on XP this call will do nothing).
+    EventRegisterChrome();
+  }
+}
+
+TraceEventETWExport::~TraceEventETWExport() {
+  EventUnregisterChrome();
+}
+
+// static
+TraceEventETWExport* TraceEventETWExport::GetInstance() {
+  return Singleton<TraceEventETWExport,
+                   StaticMemorySingletonTraits<TraceEventETWExport>>::get();
+}
+
+// static
+void TraceEventETWExport::EnableETWExport() {
+  GetInstance()->ETWExportEnabled_ = true;
+}
+
+// static
+void TraceEventETWExport::DisableETWExport() {
+  GetInstance()->ETWExportEnabled_ = false;
+}
+
+// static
+void TraceEventETWExport::AddEvent(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int num_args,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const unsigned long long* arg_values,
+    const scoped_refptr<ConvertableToTraceFormat>* convertable_values) {
+  // We bail early in case exporting is disabled or no consumer is listening.
+  if (!GetInstance()->ETWExportEnabled_ || !EventEnabledChromeEvent())
+    return;
+
+  std::string phase_string;
+  switch (phase) {
+    case TRACE_EVENT_PHASE_BEGIN:
+      phase_string = "Begin";
+      break;
+    case TRACE_EVENT_PHASE_END:
+      phase_string = "End";
+      break;
+    case TRACE_EVENT_PHASE_COMPLETE:
+      phase_string = "Complete";
+      break;
+    case TRACE_EVENT_PHASE_INSTANT:
+      phase_string = "Instant";
+      break;
+    case TRACE_EVENT_PHASE_ASYNC_BEGIN:
+      phase_string = "Async Begin";
+      break;
+    case TRACE_EVENT_PHASE_ASYNC_STEP_INTO:
+      phase_string = "Async Step Into";
+      break;
+    case TRACE_EVENT_PHASE_ASYNC_STEP_PAST:
+      phase_string = "Async Step Past";
+      break;
+    case TRACE_EVENT_PHASE_ASYNC_END:
+      phase_string = "Async End";
+      break;
+    case TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN:
+      phase_string = "Nestable Async Begin";
+      break;
+    case TRACE_EVENT_PHASE_NESTABLE_ASYNC_END:
+      phase_string = "Nestable Async End";
+      break;
+    case TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT:
+      phase_string = "Nestable Async Instant";
+      break;
+    case TRACE_EVENT_PHASE_FLOW_BEGIN:
+      phase_string = "Phase Flow Begin";
+      break;
+    case TRACE_EVENT_PHASE_FLOW_STEP:
+      phase_string = "Phase Flow Step";
+      break;
+    case TRACE_EVENT_PHASE_FLOW_END:
+      phase_string = "Phase Flow End";
+      break;
+    case TRACE_EVENT_PHASE_METADATA:
+      phase_string = "Phase Metadata";
+      break;
+    case TRACE_EVENT_PHASE_COUNTER:
+      phase_string = "Phase Counter";
+      break;
+    case TRACE_EVENT_PHASE_SAMPLE:
+      phase_string = "Phase Sample";
+      break;
+    case TRACE_EVENT_PHASE_CREATE_OBJECT:
+      phase_string = "Phase Create Object";
+      break;
+    case TRACE_EVENT_PHASE_SNAPSHOT_OBJECT:
+      phase_string = "Phase Snapshot Object";
+      break;
+    case TRACE_EVENT_PHASE_DELETE_OBJECT:
+      phase_string = "Phase Delete Object";
+      break;
+    default:
+      phase_string.push_back(phase);
+      break;
+  }
+
+  std::string arg_values_string[3];
+  for (int i = 0; i < num_args; i++) {
+    if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
+      convertable_values[i]->AppendAsTraceFormat(arg_values_string + i);
+    } else {
+      TraceEvent::TraceValue trace_event;
+      trace_event.as_uint = arg_values[i];
+      TraceEvent::AppendValueAsJSON(arg_types[i], trace_event,
+                                    arg_values_string + i);
+    }
+  }
+
+  EventWriteChromeEvent(
+      name, phase_string.c_str(), num_args > 0 ? arg_names[0] : "",
+      arg_values_string[0].c_str(), num_args > 1 ? arg_names[1] : "",
+      arg_values_string[1].c_str(), num_args > 2 ? arg_names[2] : "",
+      arg_values_string[2].c_str());
+}
+
+// static
+void TraceEventETWExport::AddCustomEvent(const char* name,
+                                         char const* phase,
+                                         const char* arg_name_1,
+                                         const char* arg_value_1,
+                                         const char* arg_name_2,
+                                         const char* arg_value_2,
+                                         const char* arg_name_3,
+                                         const char* arg_value_3) {
+  if (!GetInstance()->ETWExportEnabled_ || !EventEnabledChromeEvent())
+    return;
+
+  EventWriteChromeEvent(name, phase, arg_name_1, arg_value_1, arg_name_2,
+                        arg_value_2, arg_name_3, arg_value_3);
+}
+
+void TraceEventETWExport::Resurrect() {
+  StaticMemorySingletonTraits<TraceEventETWExport>::Resurrect();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_etw_export_win.h b/base/trace_event/trace_event_etw_export_win.h
new file mode 100644
index 0000000..0a551c3
--- /dev/null
+++ b/base/trace_event/trace_event_etw_export_win.h
@@ -0,0 +1,73 @@
+// 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.
+
+// This file contains the Windows-specific exporting to ETW.
+#ifndef BASE_TRACE_EVENT_TRACE_ETW_EXPORT_H_
+#define BASE_TRACE_EVENT_TRACE_ETW_EXPORT_H_
+
+#include "base/base_export.h"
+#include "base/trace_event/trace_event_impl.h"
+
+// Fwd.
+template <typename Type>
+struct StaticMemorySingletonTraits;
+
+namespace base {
+namespace trace_event {
+
+class BASE_EXPORT TraceEventETWExport {
+ public:
+  ~TraceEventETWExport();
+
+  // Retrieves the singleton.
+  // Note that this may return NULL post-AtExit processing.
+  static TraceEventETWExport* GetInstance();
+
+  // Enables/disables exporting of events to ETW. If disabled,
+  // AddEvent and AddCustomEvent will simply return when called.
+  static void EnableETWExport();
+  static void DisableETWExport();
+
+  static bool isETWExportEnabled() { return GetInstance()->ETWExportEnabled_; }
+
+  // Exports an event to ETW. This is mainly used in
+  // TraceLog::AddTraceEventWithThreadIdAndTimestamp to export internal events.
+  static void AddEvent(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      unsigned long long id,
+      int num_args,
+      const char** arg_names,
+      const unsigned char* arg_types,
+      const unsigned long long* arg_values,
+      const scoped_refptr<ConvertableToTraceFormat>* convertable_values);
+
+  // Exports an event to ETW. This should be used when exporting an event only
+  // to ETW. Supports three arguments to be passed to ETW.
+  // TODO(georgesak): Allow different providers.
+  static void AddCustomEvent(const char* name,
+                             char const* phase,
+                             const char* arg_name_1,
+                             const char* arg_value_1,
+                             const char* arg_name_2,
+                             const char* arg_value_2,
+                             const char* arg_name_3,
+                             const char* arg_value_3);
+
+  void Resurrect();
+
+ private:
+  bool ETWExportEnabled_;
+  // Ensure only the provider can construct us.
+  friend struct StaticMemorySingletonTraits<TraceEventETWExport>;
+  TraceEventETWExport();
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventETWExport);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_ETW_EXPORT_H_
diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc
index 72b46f9..cbeeeab 100644
--- a/base/trace_event/trace_event_impl.cc
+++ b/base/trace_event/trace_event_impl.cc
@@ -5,12 +5,12 @@
 #include "base/trace_event/trace_event_impl.h"
 
 #include <algorithm>
+#include <cmath>
 
 #include "base/base_switches.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/debug/leak_annotations.h"
-#include "base/float_util.h"
 #include "base/format_macros.h"
 #include "base/json/string_escape.h"
 #include "base/lazy_instance.h"
@@ -30,11 +30,13 @@
 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread_id_name_manager.h"
+#include "base/threading/worker_pool.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_synthetic_delay.h"
 
 #if defined(OS_WIN)
+#include "base/trace_event/trace_event_etw_export_win.h"
 #include "base/trace_event/trace_event_win.h"
 #endif
 
@@ -73,7 +75,7 @@
     512000000 / kTraceBufferChunkSize;
 const size_t kTraceEventVectorBufferChunks = 256000 / kTraceBufferChunkSize;
 const size_t kTraceEventRingBufferChunks = kTraceEventVectorBufferChunks / 4;
-const size_t kTraceEventBatchChunks = 1000 / kTraceBufferChunkSize;
+const size_t kTraceEventBufferSizeInBytes = 100 * 1024;
 // Can store results for 30 seconds with 1 ms sampling interval.
 const size_t kMonitorTraceEventBufferChunks = 30000 / kTraceBufferChunkSize;
 // ECHO_TO_CONSOLE needs a small buffer to hold the unfinished COMPLETE events.
@@ -645,7 +647,7 @@
       //        should be made into a common method.
       std::string real;
       double val = value.as_double;
-      if (IsFinite(val)) {
+      if (std::isfinite(val)) {
         real = DoubleToString(val);
         // Ensure that the number has a .0 if there's no decimal or 'e'.  This
         // makes sure that when we read the JSON back, it's interpreted as a
@@ -663,7 +665,7 @@
           // "-.1" bad "-0.1" good
           real.insert(1, "0");
         }
-      } else if (IsNaN(val)){
+      } else if (std::isnan(val)){
         // The JSON spec doesn't allow NaN and Infinity (since these are
         // objects in EcmaScript).  Use strings instead.
         real = "\"NaN\"";
@@ -1208,7 +1210,8 @@
       event_callback_category_filter_(
           CategoryFilter::kDefaultCategoryFilterString),
       thread_shared_chunk_index_(0),
-      generation_(0) {
+      generation_(0),
+      use_worker_thread_(false) {
   // Trace is enabled or disabled on one thread while other threads are
   // accessing the enabled flag. We don't care whether edge-case events are
   // traced or not, so we allow races on the enabled flag to keep the trace
@@ -1290,6 +1293,11 @@
   if (event_callback_ &&
       event_callback_category_filter_.IsCategoryGroupEnabled(category_group))
     enabled_flag |= ENABLED_FOR_EVENT_CALLBACK;
+#if defined(OS_WIN)
+  if (base::trace_event::TraceEventETWExport::isETWExportEnabled())
+    enabled_flag |= ENABLED_FOR_ETW_EXPORT;
+#endif
+
   g_category_group_enabled[category_index] = enabled_flag;
 }
 
@@ -1681,7 +1689,9 @@
 //    - The message loop will be removed from thread_message_loops_;
 //    If this is the last message loop, finish the flush;
 // 4. If any thread hasn't finish its flush in time, finish the flush.
-void TraceLog::Flush(const TraceLog::OutputCallback& cb) {
+void TraceLog::Flush(const TraceLog::OutputCallback& cb,
+                     bool use_worker_thread) {
+  use_worker_thread_ = use_worker_thread;
   if (IsEnabled()) {
     // Can't flush when tracing is enabled because otherwise PostTask would
     // - generate more trace events;
@@ -1735,6 +1745,7 @@
   FinishFlush(generation);
 }
 
+// Usually it runs on a different thread.
 void TraceLog::ConvertTraceEventsToTraceFormat(
     scoped_ptr<TraceBuffer> logged_events,
     const TraceLog::OutputCallback& flush_output_callback) {
@@ -1749,19 +1760,17 @@
     scoped_refptr<RefCountedString> json_events_str_ptr =
         new RefCountedString();
 
-    for (size_t i = 0; i < kTraceEventBatchChunks; ++i) {
+    while (json_events_str_ptr->size() < kTraceEventBufferSizeInBytes) {
       const TraceBufferChunk* chunk = logged_events->NextChunk();
-      if (!chunk) {
-        has_more_events = false;
+      has_more_events = chunk != NULL;
+      if (!chunk)
         break;
-      }
       for (size_t j = 0; j < chunk->size(); ++j) {
-        if (i > 0 || j > 0)
+        if (json_events_str_ptr->size())
           json_events_str_ptr->data().append(",\n");
         chunk->GetEventAt(j)->AppendAsJSON(&(json_events_str_ptr->data()));
       }
     }
-
     flush_output_callback.Run(json_events_str_ptr, has_more_events);
   } while (has_more_events);
 }
@@ -1785,6 +1794,16 @@
     flush_output_callback_.Reset();
   }
 
+  if (use_worker_thread_ &&
+      WorkerPool::PostTask(
+          FROM_HERE,
+          Bind(&TraceLog::ConvertTraceEventsToTraceFormat,
+               Passed(&previous_logged_events),
+               flush_output_callback),
+          true)) {
+    return;
+  }
+
   ConvertTraceEventsToTraceFormat(previous_logged_events.Pass(),
                                   flush_output_callback);
 }
@@ -1908,7 +1927,7 @@
   DCHECK(!timestamp.is_null());
 
   if (flags & TRACE_EVENT_FLAG_MANGLE_ID)
-    id ^= process_id_hash_;
+    id = MangleEventId(id);
 
   TimeTicks offset_event_timestamp = OffsetTimestamp(timestamp);
   TimeTicks now = flags & TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP ?
@@ -1971,6 +1990,15 @@
     }
   }
 
+#if defined(OS_WIN)
+  // This is done sooner rather than later, to avoid creating the event and
+  // acquiring the lock, which is not needed for ETW as it's already threadsafe.
+  if (*category_group_enabled & ENABLED_FOR_ETW_EXPORT)
+    TraceEventETWExport::AddEvent(phase, category_group_enabled, name, id,
+                                  num_args, arg_names, arg_types, arg_values,
+                                  convertable_values);
+#endif  // OS_WIN
+
   std::string console_message;
   if (*category_group_enabled &
       (ENABLED_FOR_RECORDING | ENABLED_FOR_MONITORING)) {
@@ -2177,6 +2205,10 @@
   watch_event_callback_.Reset();
 }
 
+uint64 TraceLog::MangleEventId(uint64 id) {
+  return id ^ process_id_hash_;
+}
+
 void TraceLog::AddMetadataEventsWhileLocked() {
   lock_.AssertAcquired();
 
diff --git a/base/trace_event/trace_event_impl.h b/base/trace_event/trace_event_impl.h
index efa20c4..33a85c9 100644
--- a/base/trace_event/trace_event_impl.h
+++ b/base/trace_event/trace_event_impl.h
@@ -26,6 +26,7 @@
 
 // Older style trace macros with explicit id and extra data
 // Only these macros result in publishing data to ETW as currently implemented.
+// TODO(georgesak): Update/replace these with new ETW macros.
 #define TRACE_EVENT_BEGIN_ETW(name, id, extra) \
     base::trace_event::TraceLog::AddTraceEventEtw( \
         TRACE_EVENT_PHASE_BEGIN, \
@@ -446,6 +447,8 @@
     ENABLED_FOR_MONITORING = 1 << 1,
     // Category group enabled by SetEventCallbackEnabled().
     ENABLED_FOR_EVENT_CALLBACK = 1 << 2,
+    // Category group enabled to export events to ETW.
+    ENABLED_FOR_ETW_EXPORT = 1 << 3
   };
 
   static TraceLog* GetInstance();
@@ -538,10 +541,11 @@
   // Due to the implementation of thread-local buffers, flush can't be
   // done when tracing is enabled. If called when tracing is enabled, the
   // callback will be called directly with (empty_string, false) to indicate
-  // the end of this unsuccessful flush.
+  // the end of this unsuccessful flush. Flush does the serialization
+  // on the same thread if the caller doesn't set use_worker_thread explicitly.
   typedef base::Callback<void(const scoped_refptr<base::RefCountedString>&,
                               bool has_more_events)> OutputCallback;
-  void Flush(const OutputCallback& cb);
+  void Flush(const OutputCallback& cb, bool use_worker_thread = false);
   void FlushButLeaveBufferIntact(const OutputCallback& flush_output_callback);
 
   // Called by TRACE_EVENT* macros, don't call this directly.
@@ -602,6 +606,8 @@
 
   int process_id() const { return process_id_; }
 
+  uint64 MangleEventId(uint64 id);
+
   // Exposed for unittesting:
 
   void WaitSamplingEventForTesting();
@@ -710,7 +716,9 @@
   // |generation| is used in the following callbacks to check if the callback
   // is called for the flush of the current |logged_events_|.
   void FlushCurrentThread(int generation);
-  void ConvertTraceEventsToTraceFormat(scoped_ptr<TraceBuffer> logged_events,
+  // Usually it runs on a different thread.
+  static void ConvertTraceEventsToTraceFormat(
+      scoped_ptr<TraceBuffer> logged_events,
       const TraceLog::OutputCallback& flush_output_callback);
   void FinishFlush(int generation);
   void OnFlushTimeout(int generation);
@@ -803,6 +811,7 @@
   OutputCallback flush_output_callback_;
   scoped_refptr<MessageLoopProxy> flush_message_loop_proxy_;
   subtle::AtomicWord generation_;
+  bool use_worker_thread_;
 
   DISALLOW_COPY_AND_ASSIGN(TraceLog);
 };
diff --git a/base/trace_event/trace_event_win_unittest.cc b/base/trace_event/trace_event_win_unittest.cc
index 7f1004e..d4dc854 100644
--- a/base/trace_event/trace_event_win_unittest.cc
+++ b/base/trace_event/trace_event_win_unittest.cc
@@ -92,7 +92,7 @@
   TraceEventWinTest() {
   }
 
-  void SetUp() {
+  void SetUp() override {
     bool is_xp = win::GetVersion() < base::win::VERSION_VISTA;
 
     if (is_xp) {
@@ -151,7 +151,7 @@
     EXPECT_TRUE(tracelog->IsTracing());
   }
 
-  void TearDown() {
+  void TearDown() override {
     EtwTraceProperties prop;
     if (controller_.session() != 0)
       EXPECT_HRESULT_SUCCEEDED(controller_.Stop(&prop));
diff --git a/base/trace_event/winheap_dump_provider_win.cc b/base/trace_event/winheap_dump_provider_win.cc
new file mode 100644
index 0000000..3a4fd87
--- /dev/null
+++ b/base/trace_event/winheap_dump_provider_win.cc
@@ -0,0 +1,103 @@
+// 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/winheap_dump_provider_win.h"
+
+#include <windows.h>
+
+#include "base/trace_event/process_memory_dump.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+const char kDumperFriendlyName[] = "winheap";
+
+// Report a heap dump to a process memory dump. The |heap_info| structure
+// contains the information about this heap, and |heap_name| will be used to
+// represent it in the report.
+bool ReportHeapDump(ProcessMemoryDump* pmd,
+                    const WinHeapInfo& heap_info,
+                    const std::string& heap_name) {
+  MemoryAllocatorDump* dump =
+      pmd->CreateAllocatorDump(kDumperFriendlyName, heap_name);
+  if (!dump)
+    return false;
+  dump->set_physical_size_in_bytes(heap_info.committed_size);
+  dump->set_allocated_objects_count(heap_info.block_count);
+  dump->set_allocated_objects_size_in_bytes(heap_info.allocated_size);
+  return true;
+}
+
+}  // namespace
+
+WinHeapDumpProvider* WinHeapDumpProvider::GetInstance() {
+  return Singleton<WinHeapDumpProvider,
+                   LeakySingletonTraits<WinHeapDumpProvider>>::get();
+}
+
+bool WinHeapDumpProvider::DumpInto(ProcessMemoryDump* pmd) {
+  // Retrieves the number of heaps in the current process.
+  DWORD number_of_heaps = ::GetProcessHeaps(0, NULL);
+  WinHeapInfo all_heap_info = {0};
+
+  // Try to retrieve a handle to all the heaps owned by this process. Returns
+  // false if the number of heaps has changed.
+  //
+  // This is inherently racy as is, but it's not something that we observe a lot
+  // in Chrome, the heaps tend to be created at startup only.
+  scoped_ptr<HANDLE[]> all_heaps(new HANDLE[number_of_heaps]);
+  if (::GetProcessHeaps(number_of_heaps, all_heaps.get()) != number_of_heaps)
+    return false;
+
+  // Skip the pointer to the heap array to avoid accounting the memory used by
+  // this dump provider.
+  std::set<void*> block_to_skip;
+  block_to_skip.insert(all_heaps.get());
+
+  // Retrieves some metrics about each heap.
+  for (size_t i = 0; i < number_of_heaps; ++i) {
+    WinHeapInfo heap_info = {0};
+    heap_info.heap_id = all_heaps[i];
+    GetHeapInformation(&heap_info, block_to_skip);
+
+    all_heap_info.allocated_size += heap_info.allocated_size;
+    all_heap_info.committed_size += heap_info.committed_size;
+    all_heap_info.block_count += heap_info.block_count;
+  }
+  // Report the heap dump.
+  if (!ReportHeapDump(pmd, all_heap_info, MemoryAllocatorDump::kRootHeap))
+    return false;
+
+  return true;
+}
+
+const char* WinHeapDumpProvider::GetFriendlyName() const {
+  return kDumperFriendlyName;
+}
+
+bool WinHeapDumpProvider::GetHeapInformation(
+    WinHeapInfo* heap_info,
+    const std::set<void*>& block_to_skip) {
+  CHECK(::HeapLock(heap_info->heap_id) == TRUE);
+  PROCESS_HEAP_ENTRY heap_entry;
+  heap_entry.lpData = nullptr;
+  // Walk over all the entries in this heap.
+  while (::HeapWalk(heap_info->heap_id, &heap_entry) != FALSE) {
+    if (block_to_skip.count(heap_entry.lpData) == 1)
+      continue;
+    if ((heap_entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) {
+      heap_info->allocated_size += heap_entry.cbData;
+      heap_info->block_count++;
+    } else if ((heap_entry.wFlags & PROCESS_HEAP_REGION) != 0) {
+      heap_info->committed_size += heap_entry.Region.dwCommittedSize;
+    }
+  }
+  CHECK(::HeapUnlock(heap_info->heap_id) == TRUE);
+  return true;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/winheap_dump_provider_win.h b/base/trace_event/winheap_dump_provider_win.h
new file mode 100644
index 0000000..8abac47
--- /dev/null
+++ b/base/trace_event/winheap_dump_provider_win.h
@@ -0,0 +1,53 @@
+// 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_WINHEAP_DUMP_PROVIDER_WIN_H_
+#define BASE_TRACE_EVENT_WINHEAP_DUMP_PROVIDER_WIN_H_
+
+#include <set>
+
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+namespace trace_event {
+
+// A structure containing some information about a given heap.
+struct WinHeapInfo {
+  HANDLE heap_id;
+  size_t committed_size;
+  size_t allocated_size;
+  size_t block_count;
+};
+
+// Dump provider which collects process-wide heap memory stats. This provider
+// iterates over all the heaps of the current process to gather some metrics
+// about them.
+class BASE_EXPORT WinHeapDumpProvider : public MemoryDumpProvider {
+ public:
+  static WinHeapDumpProvider* GetInstance();
+
+  // MemoryDumpProvider implementation.
+  bool DumpInto(ProcessMemoryDump* pmd) override;
+  const char* GetFriendlyName() const override;
+
+ private:
+  friend struct DefaultSingletonTraits<WinHeapDumpProvider>;
+
+  // Retrieves the information about given heap. The |heap_info| should contain
+  // a valid handle to an existing heap. The blocks contained in the
+  // |block_to_skip| set will be ignored.
+  bool GetHeapInformation(WinHeapInfo* heap_info,
+                          const std::set<void*>& block_to_skip);
+
+  WinHeapDumpProvider() {}
+  ~WinHeapDumpProvider() override {}
+
+  DISALLOW_COPY_AND_ASSIGN(WinHeapDumpProvider);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_WINHEAP_DUMP_PROVIDER_WIN_H_
diff --git a/base/trace_event/winheap_dump_provider_win_unittest.cc b/base/trace_event/winheap_dump_provider_win_unittest.cc
new file mode 100644
index 0000000..99da18a
--- /dev/null
+++ b/base/trace_event/winheap_dump_provider_win_unittest.cc
@@ -0,0 +1,27 @@
+// 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/winheap_dump_provider_win.h"
+
+#include <windows.h>
+
+#include "base/trace_event/memory_dump_session_state.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(WinHeapDumpProviderTest, DumpInto) {
+  ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+
+  WinHeapDumpProvider* winheap_dump_provider =
+      WinHeapDumpProvider::GetInstance();
+  ASSERT_NE(static_cast<WinHeapDumpProvider*>(nullptr), winheap_dump_provider);
+
+  ASSERT_TRUE(winheap_dump_provider->DumpInto(&pmd));
+}
+
+}  // namespace trace_event
+}  // namespace base